// Copyright (C) 2003-2026, Foxit Software Inc..
// All Rights Reserved.
//
// http://www.foxitsoftware.com
//
// The following code is copyrighted and contains proprietary information and trade secrets of Foxit Software Inc..
// You cannot distribute any part of Foxit PDF SDK to any third party or general public,
// unless there is a separate license agreement with Foxit Software Inc. which explicitly grants you such rights.
//
// This file contains an example to demonstrate how to use Foxit PDF SDK to create a PDF document,
// insert the text path and image objects into the created PDF document, copy shading objects,
// and save the file with inserted graphics objects.

#include "FSPDFObjC.h"

NSString *input_path = @"../input_files/";
NSString *output_path = @"../output_files/";

NSString *sn = @"bPxThFlBAYifO3yiW0C51bKbjPap1zHaf5aG5sX378TjFvB7Q0802A==";
NSString *key = @"8f3g1sGNtR8NAgfSNv+BvaJWy2fnrw36NZvzh8GUxYXvs+/YczAk4e34yqlOnmL4asgxGMO7+rlOcSHUSSKagx5g4G7VEXfkYLXnDDx77FOOedZPrFFcOCu1vT4+wOKzy1zkORq9cKtiFf44byH5sfRqf+OvELjep2teT9eF9yPCsSw2vRKljXlPy40DMP9XX1O5OTe+mSG3RvwKUMb0+RpG3YobM87j+/ynTDlJMMXw4vgwuTb1ZuAtlvkTdFz7HDLV81C6TYnn73ddHeGD3qYWBVsD4uJkDwyyH/SWr7QX0HSgVg8HSZqnab1VGdAUYxKY2vGWeOTJdu6qDGb5ZEb9O3kZZg+9LYAmUKzDfCYwfIsYZ8Y9LPC4wMx70kIq7JpNnzPvigrdshV8/ew1F0+qP/P5Z1EB53vDVrp2LVSuL873Wv4g3PzjZlNH+1qgT87hC+Buto4qsSUfP5Y2z0uApu+c/TfttCXbeMLSsw9TY1HQD3mkrZExMaQqRrAuXAcZWdvBnVuG3DCZmm8q0DLxJiCfYfViAU/AkbeKMIGaTJdrvIXBcssfde4nmU6qr0M4x4+Hs2ESddtY2QRtLAUBq/7h7GJlJHkEZr8ueaUy/6D/2vvAWz6wMLgmjlPbDTLqzfnCJylHCPtcJmu1SPPT9v1VreBX3+zNWcIT8HueyHEiUniqzwWkRKaotrnNb/zhnHLPpgaBSwKjyi8rOzzVwu/nY84G9ye4jsVjmkIRItKDrW7z22iS+QQuTwfqLVuMB0OD4jMkPCC2slzPfEeZnuh4+Rewln2qLRJVgI72zJ20OBWAelGSpO1Ii2Y3gOvojdmtUwx6R3Z1qFNWTTB25o9ytcux8BLOtTCkA8T8xaT4N339OTCsu/TmfahIDixKvr8cDa6F2WkBT8SOfv64W9PgiNv5B/BMOD2VWYaAl0N7yD0NkYYg/cDWRC4dfpdeip1jrr0k3mND0oSpIkxC+FicZbaYYwRdtJ9OSVWJ5OE0voLv8HgLze8mw6s4TrN3z+a2NQCveMa2VRN7YcEF7agPrvb/qU+otMwHae/wM7+f+HFAaOW+WTfzfxIVFB8/A1DN0NiEX+em4G7nO5F5ZcvfYPpaaioe8Nn33BbVLtMjXqsOBeM8AXiVfpD6YO75j7BqnBUPnivvD8BxJaaIQZvVSuQmvGm0ynt03IYwE8Rq+jYsunvsZ86jh5BiUR+Nm7sK0Qe9BdZn/7jdqohMv9czfMGUAscX+xBMunFbDpcRbWVpUADcm209L8Ndek2XY7YlCMxPgPVNvfWRF2jxehib9Tpd7zB5ZIDfAEH9zrpLfp29DLvCh2Yx8mH7xxdKG1O9Q0GdHphYHhej6smAcPm68R0GUQaTOLfXqNpueGJC1GAOI3Y4swjyt7jMTWcibnKLzwukWE5rnEDhn5n64JnyUM0ZFkRmtOiV";

void AddTextObjects(FSPDFPage *page) {
    long position = [page getLastGraphicsObjectPosition:FSGraphicsObjectTypeText];
    FSTextObject *text_object = [FSTextObject create];

    text_object.fillColor = 0xFFFF7F00;

    // Prepare text state
    FSTextState *state = [[FSTextState alloc] init];
    state.font_size = 80.0f;
    FSFont *font = [[FSFont alloc] initWithName:@"Simsun" styles:FSFontStylesSmallCap charset:FSFontCharsetGB2312 weight:0];
    state.font = font;
    state.textmode = FSTextStateModeFill;
    [text_object setTextState:page text_state:state is_italic:NO weight:750];

    // Set text.
    text_object.text = @"Foxit Software";
    long last_position = [page insertGraphicsObject:position graphics_object:text_object];

    FSRectF *rect = [text_object getRect];
    float offset_x = ([page getWidth] - (rect.right - rect.left)) / 2;
    float offset_y = [page getHeight] * 0.8f - (rect.top - rect.bottom) / 2;
    [text_object transform:[[FSMatrix2D alloc] initWithA1:1 b1:0 c1:0 d1:1 e1:offset_x f1:offset_y] need_transform_clippath:NO];

    // Generate content
    [page generateContent];

    // Clone a text object from the old text object.
    text_object = [[text_object clone] getTextObject];

    state.font_size = 48;
    font = [[FSFont alloc] initWithFont_id:FSFontStdIDTimes];
    state.textmode = FSTextStateModeFillStrokeClip;
    state.font = font;
    [text_object setTextState:page text_state:state is_italic:YES weight:750];

    text_object.text = @"www.foxitsoftware.com";
    text_object.fillColor = 0xFFAAAAAA;
    text_object.strokeColor = 0xFFF68C21;
    [page insertGraphicsObject:last_position graphics_object:text_object];

    rect = [text_object getRect];
    offset_x = ([page getWidth] - (rect.right - rect.left)) / 2;
    offset_y = [page getHeight] * 0.618f - (rect.top - rect.bottom) / 2;
    [text_object transform:[[FSMatrix2D alloc] initWithA1:1 b1:0 c1:0 d1:1 e1:offset_x f1:offset_y] need_transform_clippath:NO];

    // Generate content
    [page generateContent];

    //Show how to get the characters' information of text object.
    int text_object_charcount = [text_object getCharCount];
    NSString* record_content = [NSString new];
    NSString* temp_content = [NSString stringWithFormat:@"The new text object has %d characters.\r\n", text_object_charcount];
    record_content = [record_content stringByAppendingString:temp_content];

    for (int i = 0; i < text_object_charcount; i++) {
	    //The character's position.
        FSPointF* char_pos = [text_object getCharPos:i];
        //The character's width.
        float width = [text_object getCharWidthByIndex:i];
        //The character's height.
        float height = [text_object getCharHeightByIndex:i];

        NSString* char_info = [NSString stringWithFormat:@"The position of the %d characters is (%f, %f).The width and height of the characters is (%f, %f).\r\n", i, char_pos.x, char_pos.y, width, height];
        record_content = [record_content stringByAppendingString:char_info];
    }

    NSString *output_directory = [output_path stringByAppendingString:@"graphics_objects/"];
    NSString* save_txt_path = [NSString  stringWithFormat:@"%@%@", output_directory, @"text_objects_info.txt"];
    if ([record_content writeToFile:save_txt_path atomically:YES encoding:NSUTF8StringEncoding error:nil]) {
        NSLog(@"Success: save text objects information to %@", save_txt_path);
    } else {
        NSLog(@"Fail: save %@", save_txt_path);
    }
}

void AddImageObjects(FSPDFPage *page, NSString *image_file) {
    long position = [page getLastGraphicsObjectPosition:FSGraphicsObjectTypeImage];
    FSImage *image = [[FSImage alloc] initWithPath:image_file];
    FSImageObject *image_object = [FSImageObject create:[page getDocument]];
    [image_object setImage:image frame_index:0];

    float width = [image getWidth];
    float height = [image getHeight];

    float page_width = [page getWidth];
    float page_height = [page getHeight];

    // Please notice the matrix value.
    image_object.matrix = [[FSMatrix2D alloc] initWithA1:width b1:0 c1:0 d1:height e1:(page_width - width) / 2.0f f1:(page_height - height) / 2.0f];

    [page insertGraphicsObject:position graphics_object:image_object];
    [page generateContent];
}

void AddPieces(FSPDFPage *page, FSShadingObject *orignal_pieces, const FSRectF *dst_rect) {
    long position = [page getFirstGraphicsObjectPosition:FSGraphicsObjectTypeAll];
    FSShadingObject *pieces = [[orignal_pieces clone] getShadingObject];

    FSRectF *piece_rect = [pieces getRect];

    // Calculates the transformation matrix between dst_rect and  piece_rect.
    float a = (dst_rect.right - dst_rect.left) / (piece_rect.right - piece_rect.left);
    float d = (dst_rect.top - dst_rect.bottom) / (piece_rect.top - piece_rect.bottom);
    float e = dst_rect.left - piece_rect.left * a;
    float f = dst_rect.top - piece_rect.top * d;

    // Transform rect.
    [pieces transform:[[FSMatrix2D alloc] initWithA1:a b1:0 c1:0 d1:d e1:e f1:f] need_transform_clippath:NO];
    [page insertGraphicsObject:position graphics_object:pieces];
    [page generateContent];
}

void AddPathObjects(FSPDFPage *page, FSShadingObject *black_pieces, FSShadingObject *white_pieces) {
    long position = [page getLastGraphicsObjectPosition:FSGraphicsObjectTypePath];
    FSPathObject *path_object = [FSPathObject create];
    FSPath *path = [[FSPath alloc] init];
    float page_width = [page getWidth];
    float page_height = [page getHeight];

    float width = page_width > page_height ? page_height / 20.0f : page_width / 20.0f;
    float start_x = (page_width - width * 18.0f) / 2.0f;
    float start_y = (page_height - width * 18.0f) / 2.0f;

    // Draw a chess board
    for (int i = 0; i < 19; i++) {
        float x1 = start_x;
        float y1 = i * width + start_y;

        float x2 = start_x + 18 * width;
        FSPointF *point = [[FSPointF alloc] init];
        [point set:x1 y:y1];
        [path moveTo:point];
        [point set:x2 y:y1];
        [path lineTo:point];

        x1 = i * width + start_x;
        y1 = start_y;

        float y2 = 18 * width + start_y;
        [point set:x1 y:y1];
        [path moveTo:point];
        [point set:x1 y:y2];
        [path lineTo:point];
    }

    int star[3] = {3, 9, 15};
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            FSRectF *rect = [[FSRectF alloc] initWithLeft1:start_x + star[i] * width - width / 12 bottom1:start_y + star[j] * width - width / 12 right1:start_x + star[i] * width + width / 12 top1:start_y + star[j] * width + width / 12];
            [path appendEllipse:rect];
        }
    }
    path_object.pathData = path;

    path_object.fillColor = 0xFF000000;
    path_object.fillMode = FSFillModeAlternate;
    path_object.strokeState = true;
    path_object.strokeColor = 0xFF000000;

    [page insertGraphicsObject:position graphics_object:path_object];
    [page generateContent];

    // Draw pieces
    FSPointF *point00 = [[FSPointF alloc] init];
    [point00 set:3 y:3];
    FSPointF *point01 = [[FSPointF alloc] init];
    [point01 set:3 y:7];
    FSPointF *point02 = [[FSPointF alloc] init];
    [point02 set:3 y:15];
    FSPointF *point03 = [[FSPointF alloc] init];
    [point03 set:13 y:2];
    FSPointF *point04 = [[FSPointF alloc] init];
    [point04 set:13 y:16];
    FSPointF *point05 = [[FSPointF alloc] init];
    [point05 set:13 y:17];
    FSPointF *point06 = [[FSPointF alloc] init];
    [point06 set:15 y:16];
    FSPointF *point07 = [[FSPointF alloc] init];
    [point07 set:16 y:16];

    FSPointF *point10 = [[FSPointF alloc] init];
    [point10 set:11 y:16];
    FSPointF *point11 = [[FSPointF alloc] init];
    [point11 set:12 y:14];
    FSPointF *point12 = [[FSPointF alloc] init];
    [point12 set:14 y:4];
    FSPointF *point13 = [[FSPointF alloc] init];
    [point13 set:14 y:15];
    FSPointF *point14 = [[FSPointF alloc] init];
    [point14 set:15 y:3];
    FSPointF *point15 = [[FSPointF alloc] init];
    [point15 set:15 y:9];
    FSPointF *point16 = [[FSPointF alloc] init];
    [point16 set:15 y:15];
    FSPointF *point17 = [[FSPointF alloc] init];
    [point17 set:16 y:15];

    NSArray *pieces1 = [[NSArray alloc] initWithObjects:point00, point01, point02, point03, point04, point05, point06, point07, nil];
    NSArray *pieces2 = [[NSArray alloc] initWithObjects:point10, point11, point12, point13, point14, point15, point16, point17, nil];
    NSArray *pieces_vector = [[NSArray alloc] initWithObjects:pieces1, pieces2, nil];

    for (int k = 0; k < [pieces_vector count]; k++) {
        for (int i = 0; i < [pieces1 count]; i++) {
            FSPointF *point = pieces_vector[k][i];
            int x = point.x;
            int y = point.y;
            AddPieces(page, k % 2 ? white_pieces : black_pieces, [[FSRectF alloc] initWithLeft1:start_x + x * width - width / 2.f bottom1:start_y + y * width - width / 2.f right1:start_x + x * width + width / 2.f top1:start_y + y * width + width / 2.f]);
        }
    }
}

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        NSString *output_directory = [output_path stringByAppendingString:@"graphics_objects/"];
        NSString *input_file = [input_path stringByAppendingString:@"graphics_objects.pdf"];

        NSFileManager *fileManager = [NSFileManager defaultManager];
        BOOL isDir = NO;
        if ([fileManager fileExistsAtPath:output_directory isDirectory:&isDir]) {
            if (!isDir) {
                NSError *error = nil;
                if (![fileManager removeItemAtPath:output_directory error:&error] || error) {
                    return -1;
                }
                if (![fileManager createDirectoryAtPath:output_directory withIntermediateDirectories:YES attributes:nil error:&error] || error) {
                    return -1;
                }
            }
        } else {
            NSError *error = nil;
            if (![fileManager createDirectoryAtPath:output_directory withIntermediateDirectories:YES attributes:nil error:&error] || error) {
                return -1;
            }
        }

        // Initialize library
        FSErrorCode errorCode = [FSLibrary initialize:sn key:key];
        if (errorCode != FSErrSuccess) {
            NSLog(@"Library Initialize Error: %ld", errorCode);
            return -1;
        }

        @try {
            FSPDFDoc *doc = [[FSPDFDoc alloc] initWithPath:input_file];
            errorCode = [doc load:@""];
            if (errorCode != FSErrSuccess) {
                NSLog(@"The Doc [%@] Error: %ld\n", input_file, errorCode);
                return 1;
            }

            // Get original shading objects from PDF page.
            FSPDFPage *original_page = [doc getPage:0];
            [original_page startParse:FSPDFPageParsePageNormal pause:NULL is_reparse:NO];
            long position = [original_page getFirstGraphicsObjectPosition:FSGraphicsObjectTypeShading];
            if (!position)
                return 1;
            FSShadingObject *black_pieces = [[original_page getGraphicsObject:position] getShadingObject];
            position = [original_page getNextGraphicsObjectPosition:position filter:FSGraphicsObjectTypeShading];
            FSShadingObject *white_pieces = [[original_page getGraphicsObject:position] getShadingObject];

            // Add a new PDF page and insert text objects.
            FSPDFPage *page = [doc insertPageWithType:0 size:FSPDFPageSizeLetter];
            AddTextObjects(page);

            // Add a new PDF page and insert image objects.
            page = [doc insertPageWithType:1 size:FSPDFPageSizeLetter];
            NSString *image_file = [input_path stringByAppendingString:@"sdk.png"];
            AddImageObjects(page, image_file);

            // Add a new PDF page and insert path objects, and copy shading objects.
            page = [doc insertPageWithType:2 size:FSPDFPageSizeLetter];
            AddPathObjects(page, black_pieces, white_pieces);

            NSString *output_file = [output_directory stringByAppendingString:@"graphics_objects.pdf"];
            [doc saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
            NSLog(@"Add graphics objects to PDF file.");

            // Remove text objects from PDF page.
            page = [doc getPage:0];
            [page startParse:FSTextPageParseTextNormal pause:nil is_reparse:false];
            position = [page getFirstGraphicsObjectPosition:FSGraphicsObjectTypeAll];
            while(position > 0){
                FSGraphicsObject *obj = [page getGraphicsObject:position];
                if([obj getType] == FSGraphicsObjectTypeText){
                    FSTextObject *textobj = [obj getTextObject];
                    NSString *s = [textobj getText];
                    if([s length] > 0){
                        [page removeGraphicsObject:obj];
                        position = [page getFirstGraphicsObjectPosition:FSGraphicsObjectTypeAll];
                        continue;
                    }
                }
                else if([obj getType] == FSGraphicsObjectTypeFormXObject){
                    FSFormXObject *formxobj = [obj getFormXObject];
                    FSGraphicsObjects *graphicsObjects_form = [formxobj getGraphicsObjects];
                    long pos = [graphicsObjects_form getFirstGraphicsObjectPosition:FSGraphicsObjectTypeText];
                    if(pos > 0){
                        FSGraphicsObject *graphics_obj = [page getGraphicsObject:pos];
                        FSTextObject *textobj = [graphics_obj getTextObject];
                        if([textobj getType] == FSGraphicsObjectTypeText){
                            NSString *s = [textobj getText];
                            if([s length] > 0){
                                [page removeGraphicsObject:obj];
                                position = [page getFirstGraphicsObjectPosition:FSGraphicsObjectTypeAll];
                                continue;
                            }
                        }
                    }
                }
                position = [page getNextGraphicsObjectPosition:position filter:FSGraphicsObjectTypeAll];
            }
            [page generateContent];

            output_file = [output_directory stringByAppendingString:@"graphics_objects_remove_text_objects.pdf"];
            [doc saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
            NSLog(@"Remove text objects from PDF file.");

        }
        @catch (NSException *e) {
            NSLog(@"Unknown Exception, %@", e);
        }
    }
    [FSLibrary destroy];
    return 0;
}
