> 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/ios/get-started/samples/textextracttest.md).

# TextExtract

Sample code in Swift and Obj-C for using Apryse iOS SDK to read a PDF (parse and extract text).

Sample code in Swift and Obj-C for using Apryse iOS SDK to read a PDF (parse and extract text). If you'd like to search text on PDF pages, see our code sample for [text search](/ios/get-started/samples/textsearchtest.md).

Learn more about our full [PDF Data Extraction SDK Capabilities](https://apryse.com/capabilities/extraction).

To start your free trial, [get stated with iOS SDK](/ios/get-started/get-started.md).

{% tabs %}
{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

#import <OBJC/PDFNetOBJC.h>
#import <Foundation/Foundation.h>

// This sample illustrates the basic text extraction capabilities of PDFNet.

// A utility method used to dump all text content in the console window.
void DumpAllText(PTElementReader *reader) 
{
    PTElement *element; 
    while ((element = [reader Next]) != NULL)
    {
        switch ([element GetType]) 
        {
        case e_pttext_begin: 
            NSLog(@"--> Text Block Begin");
            break;
        case e_pttext_end:
            NSLog(@"--> Text Block End");
            break;
        case e_pttext:
            {
                PTPDFRect * bbox = [element GetBBox];
                NSLog(@"--> BBox: %f, %f, %f, %f", [bbox GetX1], [bbox GetY1], [bbox GetX2], [bbox GetY2]);

                NSLog(@"%@", [element GetTextString]);
            }
            break;
        case e_pttext_new_line:
            NSLog(@"--> New Line");
            break;
        case e_ptform:                // Process form XObjects
            [reader FormBegin]; 
            DumpAllText(reader);
            [reader End]; 
            break;
        default:
            break;
        }
    }
}

// A helper method for ReadTextFromRect
void RectTextSearch(PTElementReader *reader, PTPDFRect * pos, NSString **srch_str)
{            
    PTElement *element; 
    while ((element = [reader Next]) != NULL)
    {
        switch ([element GetType]) 
        {
        case e_pttext:
            {
                PTPDFRect * bbox = [element GetBBox];
                if([bbox IntersectRect: bbox rect2: pos]) 
                {
                    NSString *arr = [element GetTextString];
                    *srch_str = [*srch_str stringByAppendingString: arr];
                    *srch_str = [*srch_str stringByAppendingString: @"\n"]; // add a new line?
                }
                break;
            }
        case e_pttext_new_line:
            {
                break;
            }
        case e_ptform: // Process form XObjects
            {
                [reader FormBegin]; 
                RectTextSearch(reader, pos, &(*srch_str));
                [reader End]; 
                break; 
            }
        default:
            break;
        }
    }
}

// A utility method used to extract all text content from
// a given selection rectangle. The rectangle coordinates are
// expressed in PDF user/page coordinate system.
NSString* ReadTextFromRect(PTPage *page, PTPDFRect * pos, PTElementReader *reader)
{
    NSString *srch_str = @"";
    [reader Begin: page];
    RectTextSearch(reader, pos, &srch_str);
    [reader End];
    return srch_str;
}


void PrintStyle(PTTextExtractorStyle *s)
{
    NSArray *rgb = [s GetColor];
    NSString * name = [s GetFontName ];
    const char* font_family = [name UTF8String];
    double font_size = [s GetFontSize];
    const char * san_serif = ([s IsSerif]) ? " sans-serif;" : "";
    int R = [rgb[0] intValue];
    int G = [rgb[1] intValue];
    int B = [rgb[2] intValue];
    printf(" style=\"font-family:%s; font-size:%g;%s color:#%02X%02X%02X;\"", font_family, font_size, san_serif, [rgb[0] intValue], [rgb[1] intValue], [rgb[2] intValue]);
}

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int ret = 0;
        [PTPDFNet Initialize: 0];

        bool example1_basic     = false;
        bool example2_xml       = false;
        bool example3_wordlist  = false;
        bool example4_advanced  = true;
        bool example5_low_level = false;

        // Sample code showing how to use high-level text extraction APIs.
        @try
        {
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/newsletter.pdf"];
            [doc InitSecurityHandler];

            PTPage *page = [doc GetPage: 1];
            if (![page IsValid]){
                NSLog(@"Page not found.");
                return 1;
            }

            PTTextExtractor *txt = [[PTTextExtractor alloc] init];
            [txt Begin: page clip_ptr: 0 flags: 0]; // Read the page.
            // Other options you may want to consider...
            // txt.Begin(*itr, 0, TextExtractor::e_no_dup_remove);
            // txt.Begin(*itr, 0, TextExtractor::e_remove_hidden_text);


            // Example 1. Get all text on the page in a single string.
            // Words will be separated with space or new line characters.
            if (example1_basic) 
            {
                // Get the word count.
                NSLog(@"Word Count: %d", [txt GetWordCount]);

                NSString *text = [txt GetAsText: YES];
                NSLog(@"\n\n- GetAsText --------------------------\n%@", text);
                NSLog(@"-----------------------------------------------------------");
            }

            // Example 2. Get XML logical structure for the page.
            if (example2_xml) 
            {
                NSString *text = [txt GetAsXML: e_ptwords_as_elements | e_ptoutput_bbox | e_ptoutput_style_info];
                NSLog(@"\n\n- GetAsXML  --------------------------\n %@", text);
                NSLog(@"-----------------------------------------------------------");
            }

            // Example 3. Extract words one by one.
            if (example3_wordlist) 
            {
                PTTextExtractorLine *line = [txt GetFirstLine];
                PTWord *word;
                for (; [line IsValid]; line=[line GetNextLine])    {
                    for (word=[line GetFirstWord]; [word IsValid]; word=[word GetNextWord]) {
                        NSLog(@"%@", [word GetString]);
                    }
                }
                NSLog(@"-----------------------------------------------------------");
            }

            // Example 4. A more advanced text extraction example. 
            // The output is XML structure containing paragraphs, lines, words, 
            // as well as style and positioning information.
            if (example4_advanced) 
            {
                PTPDFRect * b, *q;
                int cur_flow_id=-1, cur_para_id=-1;

                NSString *uni_str;
                PTTextExtractorLine *line;
                PTWord *word;
                PTTextExtractorStyle *s, *line_style;

                printf("<PDFText>\n");
                // For each line on the page...
                for (line=[txt GetFirstLine]; [line IsValid]; line=[line GetNextLine])
                {
                    if ( [line GetNumWords] == 0 )
                    {
                        continue;
                    }
                    
                    if (cur_flow_id != [line GetFlowID]) {
                        if (cur_flow_id != -1) {
                            if (cur_para_id != -1) {
                                cur_para_id = -1;
                                printf("</Para>\n");
                            }
                            printf("</Flow>\n");
                        }
                        cur_flow_id = [line GetFlowID];
                        printf("<Flow id=\"%d\">\n", cur_flow_id);
                    }

                    if (cur_para_id != [line GetParagraphID]) {
                        if (cur_para_id != -1)
                            printf("</Para>\n");
                        cur_para_id = [line GetParagraphID];
                        printf("<Para id=\"%d\">\n", cur_para_id);
                    }    

                    b = [line GetBBox];
                    line_style = [line GetStyle];
                    printf("<Line box=\"%.2f, %.2f, %.2f, %.2f\"", [b GetX1], [b GetY1], [b GetX2], [b GetY2]);
                    PrintStyle(line_style);
                    printf(" cur_num=\"%d\"", [line GetCurrentNum]);
                    printf(">\n");

                    // For each word in the line...
                    for (word=[line GetFirstWord]; [word IsValid]; word=[word GetNextWord])
                    {
                        // Output the bounding box for the word.
                        q = [word GetBBox];
                        printf("<Word box=\"%.2f, %.2f, %.2f, %.2f\"", [q GetX1], [q GetY1], [q GetX2], [q GetY2]);
                        printf(" cur_num=\"%d\"", [word GetCurrentNum]);
                        
                        int sz = [word GetStringLen];
                        if (sz == 0) continue;

                        // If the word style is different from the parent style, output the new style.
                    
                        s = [word GetStyle];    
                        if(![s isEqualTo:line_style]){
                            PrintStyle(s);
                        }

                        uni_str = [word GetString];
                        printf(">%s", [uni_str UTF8String]);
                        printf("</Word>\n");
                    }
                    printf("</Line>\n");
                }

                if (cur_flow_id != -1) {
                    if (cur_para_id != -1) {
                        cur_para_id = -1;
                        printf("</Para>\n");
                    }
                    printf("</Flow>\n");
                }
                printf("</PDFText>\n");
            }
        }
        @catch(NSException *e)
        {
            NSLog(@"%@", e.reason);
            ret = 1;
        }

        if(example5_low_level)
        {
            @try
            {
                PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/newsletter.pdf"];
                [doc InitSecurityHandler];

                // Example 1. Extract all text content from the document

                PTElementReader *reader = [[PTElementReader alloc] init];
                //  Read every page
                PTPageIterator *itr;
                for (itr=[doc GetPageIterator: 1]; [itr HasNext]; [itr Next]) 
                {                
                    [reader Begin: [itr Current]];
                    DumpAllText(reader);
                    [reader End];
                }

                // Example 2. Extract text content based on the 
                // selection rectangle.
                NSLog(@"\n----------------------------------------------------");
                NSLog(@"\nExtract text based on the selection rectangle.");
                NSLog(@"\n----------------------------------------------------\n");

                PTPage *first_page = [doc GetPage: 1];
                PTPDFRect * rect1 = [[PTPDFRect alloc] initWithX1: 27 y1: 392 x2: 563 y2: 534];
                NSString *s1 = ReadTextFromRect(first_page, rect1, reader);
                NSLog(@"\nField 1: %@", s1);

                PTPDFRect * rect2 = [[PTPDFRect alloc] initWithX1: 28 y1: 551 x2: 106 y2: 623];
                s1 = ReadTextFromRect(first_page, rect2, reader);
                NSLog(@"\nField 2: %@", s1);

                PTPDFRect * rect3 = [[PTPDFRect alloc] initWithX1: 208 y1: 550 x2: 387 y2: 621];
                s1 = ReadTextFromRect(first_page, rect3, reader);
                NSLog(@"\nField 3: %@", s1);

                // ... 
                NSLog(@"Done.");
            }
            @catch(NSException *e)
            {
                NSLog(@"%@", e.reason);
                ret = 1;
            }
        }
        [PTPDFNet Terminate: 0];
        return ret;
    }
}
```

{% endcode %}
{% endtab %}

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

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

import PDFNet
import Foundation

// This sample illustrates the basic text extraction capabilities of PDFNet.

// A utility method used to dump all text content in the console window.
func DumpAllText(_ reader: PTElementReader) {
    while let element = reader.next() {
        switch element.getType() {
        case e_pttext_begin:
            print("--> Text Block Begin")
        case e_pttext_end:
            print("--> Text Block End")
        case e_pttext_obj:
            let bbox: PTPDFRect = element.getBBox()
            print("--> BBox: \(bbox.getX1()), \(bbox.getY1()), \(bbox.getX2()), \(bbox.getY2())")
            print("\(element.getTextString()!)")
        case e_pttext_new_line:
            print("--> New Line")
        case e_ptform:
            // Process form XObjects
            reader.formBegin()
            DumpAllText(reader)
            reader.end()
        default:
            break
        }
    }
}

// A helper method for ReadTextFromRect
func RectTextSearch(reader: PTElementReader, pos: PTPDFRect, srch_str: inout String) {
    while let element = reader.next() {
        switch element.getType() {
        case e_pttext_obj:
            let bbox: PTPDFRect = element.getBBox()
            if bbox.intersect(bbox, rect2: pos) {
                let arr = element.getTextString()
                srch_str += (arr ?? "")
                srch_str += ("\n")    // add a new line?
            }
        case e_pttext_new_line:
            break
        case e_ptform:
            // Process form XObjects
            reader.formBegin()
            RectTextSearch(reader: reader, pos: pos, srch_str: &srch_str)
            reader.end()
        default:
            break
        }
    }
}

// A utility method used to extract all text content from
// a given selection rectangle. The rectangle coordinates are
// expressed in PDF user/page coordinate system.
func ReadTextFromRect(page: PTPage, pos: PTPDFRect, reader: PTElementReader) -> String {
    var srch_str = ""
    reader.begin(page)
    RectTextSearch(reader: reader, pos: pos, srch_str: &srch_str)
    reader.end()
    return srch_str
}

func PrintStyle(_ s: PTTextExtractorStyle) {
    let rgb: NSMutableArray = s.getColor()
    print(" style=\"font-family:\(s.getFontName()!); font-size:\(s.getFontSize()); sans-serif: \(s.isSerif()); color: #\(rgb[0]), \(rgb[1]), \(rgb[2])\"")
}

func runTextExtractTest() -> Int {
    return autoreleasepool {
        var ret = 0
        
        
        let example1_basic = true
        let example2_xml = true
        let example3_wordlist = true
        let example4_advanced = true
        let example5_low_level = false
        
        // Sample code showing how to use high-level text extraction APIs.
        do {
            try PTPDFNet.catchException {
                let doc: PTPDFDoc = PTPDFDoc(filepath: Bundle.main.path(forResource: "newsletter", ofType: "pdf"))
                doc.initSecurityHandler()
                
                guard let page: PTPage = doc.getPage(1) else {
                    print("Page not found.")
                    ret = 1
                    return
                }
                
                let txt: PTTextExtractor = PTTextExtractor()
                txt.begin(page, clip_ptr: nil, flags: 0)    // Read the page.
                // Other options you may want to consider...
                // txt.begin(page, nil, e_ptno_dup_remove);
                // txt.begin(page, nil, e_ptremove_hidden_text);
                
                // Example 1. Get all text on the page in a single string.
                // Words will be separated with space or new line characters.
                if example1_basic {
                    // Get the word count.
                    print("Word Count: \(txt.getWordCount())")
                    
                    let text: String = txt.getAsText(true)
                    print("\n\n- GetAsText --------------------------\n\(text)")
                    print("-----------------------------------------------------------")
                }
                
                // Example 2. Get XML logical structure for the page.
                if example2_xml {
                    let text: String = txt.getAsXML(e_ptwords_as_elements.rawValue | e_ptoutput_bbox.rawValue | e_ptoutput_style_info.rawValue)
                    print("\n\n- GetAsXML  --------------------------\n\(text)")
                    print("-----------------------------------------------------------")
                }
                
                // Example 3. Extract words one by one.
                if example3_wordlist {
                    var line: PTTextExtractorLine = txt.getFirstLine()
                    while line.isValid() {
                        var word: PTWord = line.getFirstWord()
                        while word.isValid() {
                            print("\(word.getString()!)")
                            word = word.getNext()
                        }
                        line = line.getNext()
                    }
                    print("-----------------------------------------------------------")
                }
                
                // Example 4. A more advanced text extraction example.
                // The output is XML structure containing paragraphs, lines, words,
                // as well as style and positioning information.
                if example4_advanced {
                    var b: PTPDFRect
                    var q: PTPDFRect
                    var cur_flow_id = -1
                    var cur_para_id = -1
                    
                    var uni_str = ""
                    var line: PTTextExtractorLine
                    var word: PTWord
                    var s: PTTextExtractorStyle
                    var line_style: PTTextExtractorStyle
                    
                    // For each line on the page...
                    line = txt.getFirstLine()
                    while line.isValid() {
                        if line.getNumWords() == 0 {
                            continue
                        }
                        if cur_flow_id != line.getFlowID() {
                            if cur_flow_id != -1 {
                                if cur_para_id != -1 {
                                    cur_para_id = -1
                                    print("</Para>")
                                }
                                print("</Flow>\n")
                            }
                            cur_flow_id = Int(line.getFlowID())
                            print("<Flow id=\", \(cur_flow_id)\">\n")
                        }
                        if cur_para_id != line.getParagraphID() {
                            if cur_para_id != -1 {
                                print("</Para>\n")
                            }
                            cur_para_id = Int(line.getParagraphID())
                            print("<Para id=\", \(cur_para_id)\">\n")
                        }
                        
                        b = line.getBBox()
                        line_style = line.getStyle()
                        print("<Line box=\"\(b.getX1()), \(b.getY1()), \(b.getX2()), \(b.getY2())\"")
                        PrintStyle(line_style)
                        print(">\n")
                        
                        // For each word in the line...
                        word = line.getFirstWord()
                        while word.isValid() {
                            // Output the bounding box for the word.
                            q = word.getBBox()
                            print("<Word box=\"\(q.getX1()), \(q.getY1()), \(q.getX2()), \(q.getY2())\"")
                            let sz = word.getStringLen()
                            if sz == 0 {
                                continue
                            }
                            
                            // If the word style is different from the parent style, output the new style.
                            s = word.getStyle()
                            if s != line_style {
                                PrintStyle(s)
                            }
                            
                            uni_str = word.getString()
                            print(">\(uni_str)")
                            print("</Word>\n")
                            word = word.getNext()
                        }
                        print("</Line>\n")
                        line = line.getNext()
                    }
                    if cur_flow_id != -1 {
                        if cur_para_id != -1 {
                            cur_para_id = -1
                            print("</Para>\n")
                        }
                        print("</Flow>\n")
                    }
                }
            }
        } catch let e as NSError {
            print("\(e)")
            ret = 1
        }
        
        if example5_low_level {
//            do {
//                try PTPDFNet.catchException {
//                    let doc: PTPDFDoc = PTPDFDoc(filepath: Bundle.main.path(forResource: "newsletter", ofType: "pdf"))
//                    doc.initSecurityHandler()
//
//                    // Example 1. Extract all text content from the document
//
//                    let reader: PTElementReader = PTElementReader()
//                    //  Read every page
//                    let itr: PTPageIterator = doc.getPageIterator(1)
//                    while itr.hasNext() {
//                        reader.begin(itr.current())
//                        DumpAllText(reader)
//                        reader.end()
//                        itr.next()
//                    }
//
//                    // Example 2. Extract text content based on the
//                    // selection rectangle.
//                    print("\n----------------------------------------------------")
//                    print("\nExtract text based on the selection rectangle.")
//                    print("\n----------------------------------------------------\n")
//
//                    let first_page: PTPage = doc.getPageIterator(1).current()
//                    let rect1: PTPDFRect = PTPDFRect(x1: 27, y1: 392, x2: 563, y2: 534)
//                    var s1: String = ReadTextFromRect(page: first_page, pos: rect1, reader: reader)
//                    print("\nField 1: \(s1)")
//
//                    let rect2: PTPDFRect = PTPDFRect(x1: 28, y1: 551, x2: 106, y2: 623)
//                    s1 = ReadTextFromRect(page: first_page, pos: rect2, reader: reader)
//                    print("\nField 2: \(s1)")
//
//                    let rect3: PTPDFRect = PTPDFRect(x1: 208, y1: 550, x2: 387, y2: 621)
//                    s1 = ReadTextFromRect(page: first_page, pos: rect3, reader: reader)
//                    print("\nField 3: \(s1)")
//
//                    // ...
//                    print("Done.")
//                }
//            } catch let e as NSError {
//                print("\(e)")
//                ret = 1
//            }
        }
    
        return ret
    }
}
```

{% 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/ios/get-started/samples/textextracttest.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.
