// 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 render all PDF layers of a PDF,
// and add layers in a PDF document.

// Include Foxit SDK header files.
#include <time.h>
#include<direct.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "../../../include/fs_basictypes_c.h"
#include "../../../include/fs_common_c.h"
#include "../../../include/fs_pdfdoc_c.h"
#include "../../../include/fs_pdfpage_c.h"
#include "../../../include/fs_render_c.h"
#include "../../../include/fs_pdflayer_c.h"
#include "../../../include/fs_image_c.h"

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef NULL
#define NULL (void*)0
#endif

#define MAX_FILE_PATH 260

static const char* sn = "bPxThFlBAYifO3yiW0C51bKbjPap1zHaf5aG5sX378TjFvB7Q0802A==";
static const char* 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";

static const wchar_t* output_path = L"../output_files/";
static const wchar_t* input_path = L"../input_files/";

wchar_t output_directory[MAX_FILE_PATH];

void WriteByteString(FILE* file, const char* format, ...) {
  va_list vars;
  if (file) {
    // Get variable list
    va_start(vars, format);
    // Call vfprintf to format log data and output to log file
    vfprintf(file, format, vars);
    // End variable list
    va_end(vars);
  }
}

void Write(FILE* file, const wchar_t* format, ...) {
  va_list vars;
  if (file) {
    // Get variable list
    va_start(vars, format);
    // Call vfprintf to format log data and output to log file
    vfwprintf(file, format, vars);
    // End variable list
    va_end(vars);
  }
}

void WriteByteStringWithCount(FILE* file, int count, const char * prefix, const char * format, ...) {
  int i = 0;
  va_list vars;
  for (i = 0; i < count; i++) {
    WriteByteString(file, "%s", prefix);
  }

  if (file) {
    // Get variable list
    va_start(vars, format);
    // Call vfprintf to format log data and output to log file
    vfprintf(file, format, vars);
    // End variable list
    va_end(vars);
  }
}

void WriteWithCount(FILE* file, int count, const wchar_t * prefix, const wchar_t * format, ...) {
  int i = 0;
  va_list vars;

  for (i = 0; i < count; i++) {
    Write(file, L"%s", prefix);
  }

  if (file) {
    // Get variable list
    va_start(vars, format);
    // Call vfprintf to format log data and output to log file
    vfwprintf(file, format, vars);
    // End variable list
    va_end(vars);
  }
}

const void RenderPageToImage(FS_PDFPAGE_HANDLE page, FS_LAYERCONTEXT_HANDLE layer_content, const wchar_t* bitmap_file) {
  FS_BOOL return_isparsed;
  FSErrorCode error_code = e_FSErrSuccess;
  float f_width;
  float f_height;
  int width, height = 0;
  FSRotation return_rotation;
  FSMatrix matrix;
  FS_BITMAP_HANDLE bitmap = NULL;
  FS_RENDERER_HANDLE render = NULL;
  FS_BOOL return_is_empty;
  FS_PROGRESSIVE_HANDLE return_startrender = NULL;
  FS_IMAGE_HANDLE image = NULL;
  FS_BOOL return_addframe;
  FS_BOOL return_saveas;

  error_code = FSDK_PDFPage_IsParsed(page, &return_isparsed);
  if (error_code == e_FSErrSuccess) {
    // Parse page.
    FS_PROGRESSIVE_HANDLE return_value;
    FSDK_PDFPage_StartParse(page, e_FSParseFlagsParsePageNormal, NULL, FALSE, &return_value);
  }

  FSDK_PDFPage_GetWidth(page, &f_width);
  FSDK_PDFPage_GetHeight(page, &f_height);
  width = (int)(f_width);
  height = (int)(f_height);

  FSDK_PDFPage_GetRotation(page, &return_rotation);

  FSDK_PDFPage_GetDisplayMatrix(page, 0, 0, width, height, return_rotation, &matrix);

  // Prepare a bitmap for rendering.
  FSDK_Bitmap_Create(width, height, e_FSDIBArgb, NULL, 0, &bitmap);
  FSDK_Bitmap_FillRect(bitmap, 0xFFFFFFFF, NULL);

  // Render page.
  FSDK_Renderer_Create(bitmap, FALSE, &render);
  FSDK_LayerContext_IsEmpty(render, &return_is_empty);
  if (!return_is_empty) {
    FSDK_Renderer_SetLayerContext(render, layer_content);
  }

  FSDK_Renderer_StartRender(render, page, matrix, NULL, &return_startrender);

  FSDK_Image_Create(&image);
  FSDK_Image_AddFrame(image, bitmap, &return_addframe);
  FSDK_Image_SaveAs(image, bitmap_file, &return_saveas);
  FSDK_Bitmap_Release(bitmap);
  FSDK_Renderer_Release(render);
  FSDK_Image_Release(image);
}

char* UsgaeCodeToString(FSUsageState state) {
  switch (state) {
  case e_FSStateON:
    return "ON";
  case e_FSStateOFF:
    return "OFF";
  case e_FSStateUnchanged:
    return "Unchanged";
  case e_FSStateUndefined:
    return "Undefined";
  }
  return "Unknown";
}

void GetAllLayerNodesInformation(FS_LAYERNODE_HANDLE layer_node, int depth, FILE* file) {
  int count, i = 0;
  if (depth >= 0) {
    FS_WSTR return_getname;
    FS_BOOL return_haslayer;

    FSDK_WStr_Init(&return_getname);
    FSDK_LayerNode_GetName(layer_node, &return_getname);
    WriteWithCount(file, depth, L"\t", L"%ls", return_getname.str);

    FSDK_LayerNode_HasLayer(layer_node, &return_haslayer);
    if (return_haslayer) {
      FSUsageState state;
      FSLayerPrintData print_data;
      FSLayerZoomData zoom_data;
      FSUsageState return_getexportusage;

      FSDK_LayerNode_GetViewUsage(layer_node, &state);
      WriteByteString(file, " %s\r\n", state == e_FSStateON ? "[*]" : "[ ]");
      WriteByteStringWithCount(file, depth, "\t", "View usage state:\t%s\r\n", (const char*)UsgaeCodeToString(state));

      FSDK_LayerNode_GetExportUsage(layer_node, &return_getexportusage);
      WriteByteStringWithCount(file, depth, "\t", "Export usage state:\t%s\r\n", (const char*)UsgaeCodeToString(return_getexportusage));

      FSDK_LayerNode_GetPrintUsage(layer_node, &print_data);
      WriteByteStringWithCount(file, depth, "\t", "Print usage state:\t%s, subtype: %s\r\n", (const char*)UsgaeCodeToString(print_data.print_state),
        (const char*)print_data.subtype.str);

      FSDK_LayerNode_GetZoomUsage(layer_node, &zoom_data);
      WriteByteStringWithCount(file, depth, "\t", "Zoom usage:\tmin_factor = %.4f max_factor = %.4f\r\n\r\n", zoom_data.min_factor,
        zoom_data.max_factor);
    }
    else {
      WriteByteString(file, "\r\n");
    }
  }

  depth++;

  FSDK_LayerNode_GetChildrenCount(layer_node, &count);
  for (i = 0; i < count; i++) {
    FS_LAYERNODE_HANDLE child = NULL;
    FSDK_LayerNode_GetChild(layer_node, i, &child);
    GetAllLayerNodesInformation(child, depth, file);
  }
}

void SetAllLayerNodesInformation(FS_LAYERNODE_HANDLE layer_node) {
  FS_BOOL return_haslayer;
  int count, i = 0;
  FSDK_LayerNode_HasLayer(layer_node, &return_haslayer);
  if (return_haslayer) {
    FS_BOOL return_value;
    FSLayerPrintData print_data;
    FSLayerZoomData zoom_data;
    FS_WSTR return_getname;
    wchar_t new_name[MAX_FILE_PATH];
    FSDK_LayerNode_SetDefaultVisible(layer_node, TRUE, &return_value);
    FSDK_LayerNode_SetExportUsage(layer_node, e_FSStateUndefined, &return_value);;
    FSDK_LayerNode_SetViewUsage(layer_node, e_FSStateOFF, &return_value);

    print_data.print_state = e_FSStateON;
    print_data.subtype.str = "subtype_print";
    print_data.subtype.len = strlen("subtype_print");
    FSDK_LayerNode_SetPrintUsage(layer_node, print_data, &return_value);

    zoom_data.max_factor = 10;
    zoom_data.min_factor = 1;
    FSDK_LayerNode_SetZoomUsage(layer_node, zoom_data, &return_value);

    FSDK_WStr_Init(&return_getname);
    FSDK_LayerNode_GetName(layer_node, &return_getname);

    swprintf(new_name, MAX_FILE_PATH, L"[View_OFF_Print_ON_Export_Undefined]%ls", return_getname.str);
    FSDK_LayerNode_SetName(layer_node, new_name, &return_value);
  }

  FSDK_LayerNode_GetChildrenCount(layer_node, &count);
  for (i = 0; i < count; i++) {
    FS_LAYERNODE_HANDLE child = NULL;
    FSDK_LayerNode_GetChild(layer_node, i, &child);
    SetAllLayerNodesInformation(child);
  }
}

void SetAllLayerNodesVisible(FS_LAYERCONTEXT_HANDLE context, FS_LAYERNODE_HANDLE layer_node, FS_BOOL visible) {
  FS_BOOL return_haslayer;
  int count, i = 0;

  FSDK_LayerNode_HasLayer(layer_node, &return_haslayer);
  if (return_haslayer) {
    FS_BOOL return_value;
    FSDK_LayerContext_SetVisible(context, layer_node, FALSE, &return_value);
  }

  FSDK_LayerNode_GetChildrenCount(layer_node, &count);
  for (i = 0; i < count; i++) {
    FS_LAYERNODE_HANDLE child = NULL;
    FSDK_LayerNode_GetChild(layer_node, i, &child);
    SetAllLayerNodesVisible(context, child, visible);
  }
}

void removeWChar(wchar_t* str, wchar_t c) {
  wchar_t *src = str, *dst = str;
  while (*src) {
    if (*src != c) {
      *dst++ = *src;
    }
    src++;
  }
  *dst = L'\0';
}

void RenderAllLayerNodes(FS_PDFDOC_HANDLE doc, FS_LAYERCONTEXT_HANDLE context, FS_LAYERNODE_HANDLE layer_node, const wchar_t* pdf_name) {
  FS_BOOL return_haslayer;
  int count, i = 0;
  FSDK_LayerNode_HasLayer(layer_node, &return_haslayer);
  if (return_haslayer) {
    FS_BOOL return_value;
    int page_count, i = 0;

    FSDK_LayerContext_SetVisible(context, layer_node, TRUE, &return_value);

    FSDK_PDFDoc_GetPageCount(doc, &page_count);
    for (i = 0; i < page_count; i++) {
      FS_PDFPAGE_HANDLE page = NULL;
      wchar_t s[60];
      FS_WSTR layer_name;
	  wchar_t* strlayername = NULL;
      wchar_t file_name[MAX_FILE_PATH];

      FSErrorCode code = FSDK_PDFDoc_GetPage(doc, i, &page);

      swprintf_s(s, 60, L"%d", i);

      FSDK_WStr_Init(&layer_name);
      FSDK_LayerNode_GetName(layer_node, &layer_name);

      strlayername = layer_name.str;
      removeWChar(strlayername, L':');
      removeWChar(strlayername, L'>');
      removeWChar(strlayername, L'<');
      removeWChar(strlayername, L'=');
 
      swprintf_s(file_name, MAX_FILE_PATH, L"%lspage_%ls_layer_node_%ls.bmp", output_directory, s, strlayername);
      RenderPageToImage(page, context, file_name);
    }
  }

  FSDK_LayerNode_GetChildrenCount(layer_node, &count);
  for (i = 0; i < count; i++) {
    FS_LAYERNODE_HANDLE child = NULL;
    FSDK_LayerNode_GetChild(layer_node, i, &child);
    RenderAllLayerNodes(doc, context, child, pdf_name);
  }
  FSDK_LayerNode_HasLayer(layer_node, &return_haslayer);
  if (return_haslayer) {
    // The visibility of parent layer will affect the children layers,
    // so reset the visibility of parent layer after children have been rendered.
    FS_BOOL return_value;
    FSDK_LayerContext_SetVisible(context, layer_node, FALSE, &return_value);
  }
}

int main(int argc, char *argv[]) {
  FSErrorCode error_code = e_FSErrSuccess;
  wchar_t input_file[MAX_FILE_PATH];
  FS_PDFDOC_HANDLE doc = NULL;
  FS_LAYERTREE_HANDLE layertree = NULL;
  FS_LAYERNODE_HANDLE root = NULL;
  FS_BOOL return_value = FALSE;
  wchar_t file_info[MAX_FILE_PATH]; 
  FILE* file = NULL;
  wchar_t output_file[MAX_FILE_PATH];
  FS_BOOL return_result = FALSE;
  FS_LAYERCONTEXT_HANDLE context = NULL;
  int children_count, i = 0;
  wchar_t input_path_new[MAX_FILE_PATH];
  FS_BOOL has_layer;
  int child_count;
  FS_PDFPAGE_HANDLE page = NULL;
  wchar_t input_file_path[MAX_FILE_PATH];
  FS_PDFDOC_HANDLE newdoc = NULL;
  FS_PDFPAGE_HANDLE newpage = NULL;
  FS_PROGRESSIVE_HANDLE progressive = NULL;
  FS_LAYERNODE_HANDLE child = NULL;
  FS_LAYERNODE_HANDLE child0 = NULL;
  FS_LAYERNODE_HANDLE return_addchild;

  swprintf_s(output_directory, MAX_FILE_PATH, L"%lspdflayer/", output_path);
  _wmkdir(output_directory);

  error_code = FSDK_Library_Initialize(sn, key);
  if (error_code != e_FSErrSuccess) {
    printf("Library Initialize Error: %d\n", error_code);
    return 1;
  }

  swprintf_s(input_file, MAX_FILE_PATH, L"%lsOCTest_src.pdf", input_path);

  error_code = FSDK_PDFDoc_Create0(input_file, &doc);
  if (error_code != e_FSErrSuccess) return 1;
  error_code = FSDK_PDFDoc_Load(doc, NULL);
  if (error_code != e_FSErrSuccess) {
    FSDK_PDFDoc_Release(doc);
    wprintf(L"The Doc [%ls] Error: %d\n", input_file, error_code);
    return 1;
  }

  FSDK_LayerTree_Create(doc, &layertree);
  FSDK_LayerTree_GetRootNode(layertree, &root);
  FSDK_LayerTree_IsEmpty(layertree, &return_value);
  if (return_value) {
    printf("No layer information!\r\n");
    return 1;
  }

  // Get original information of all layer nodes.
  swprintf_s(file_info, MAX_FILE_PATH, L"%lsoriginal_layer_informations.txt", output_directory);

  _wfopen_s(&file, file_info, L"w+");
  GetAllLayerNodesInformation(root, -1, file);
  fclose(file);

  // Set new information.
  SetAllLayerNodesInformation(root);
  // Get new information.
  swprintf_s(file_info, MAX_FILE_PATH, L"%lsnew_layer_informations.txt", output_directory);
  _wfopen_s(&file, file_info, L"w+");
  GetAllLayerNodesInformation(root, -1, file);
  fclose(file);

  swprintf_s(output_file, MAX_FILE_PATH, L"%lsnew_layers.pdf", output_directory);

  error_code = FSDK_PDFDoc_SaveAs(doc, output_file, e_FSSaveFlagNoOriginal, &return_result);
  if (error_code != e_FSErrSuccess) {
    printf("Save doc error!\n");
    FSDK_PDFDoc_Release(doc);
    return 1;
  }
  // Render layer node.
  FSDK_LayerContext_Create(doc, e_FSUsageView, &context);
  SetAllLayerNodesVisible(context, root, FALSE);

  RenderAllLayerNodes(doc, context, root, output_file);

  FSDK_LayerContext_Release(context);
  FSDK_LayerTree_Release(layertree);
  layertree = 0;
  FSDK_PDFDoc_Release(doc);

  // Edit layer tree
  error_code = FSDK_PDFDoc_Create0(input_file, &doc);
  if (error_code != e_FSErrSuccess) return 1;
  error_code = FSDK_PDFDoc_Load(doc, NULL);
  if (error_code != e_FSErrSuccess) {
    FSDK_PDFDoc_Release(doc);
    wprintf(L"The Doc [%ls] Error: %d\n", input_file, error_code);
    return 1;
  }

  FSDK_LayerTree_Create(doc, &layertree);
  FSDK_LayerTree_GetRootNode(layertree, &root);
  FSDK_LayerNode_GetChildrenCount(root, &children_count);
  FSDK_LayerNode_RemoveChild(root, children_count - 1, &return_value);

  FSDK_LayerNode_GetChild(root, children_count - 2, &child);

  FSDK_LayerNode_GetChild(root, 0, &child0);
  FSDK_LayerNode_MoveTo(child, child0, 0, &return_value);

  FSDK_LayerNode_AddChild(root, 0, L"AddedLayerNode", TRUE, &return_addchild);
  FSDK_LayerNode_AddChild(root, 0, L"AddedNode", TRUE, &return_addchild);
  swprintf_s(file_info, MAX_FILE_PATH, L"%lsedit_layer_informations.txt", output_directory);
  _wfopen_s(&file, file_info, L"w+");

  GetAllLayerNodesInformation(root, -1, file);

  swprintf_s(output_file, MAX_FILE_PATH, L"%lsedit_layer_tree.pdf", output_directory);
  error_code = FSDK_PDFDoc_SaveAs(doc, output_file, e_FSSaveFlagNoOriginal, &return_result);
  if (error_code != e_FSErrSuccess) {
    printf("Save doc error!\n");
    FSDK_PDFDoc_Release(doc);
    return 1;
  }
  FSDK_LayerTree_Release(layertree);
  layertree = 0;
  FSDK_PDFDoc_Release(doc);
  fclose(file);

  // Create layer tree
  swprintf_s(input_path_new, MAX_FILE_PATH, L"%lsAboutFoxit.pdf", input_path);
  error_code = FSDK_PDFDoc_Create0(input_path_new, &doc);
  if (error_code != e_FSErrSuccess) return 1;
  error_code = FSDK_PDFDoc_Load(doc, NULL);
  if (error_code != e_FSErrSuccess) {
    FSDK_PDFDoc_Release(doc);
    wprintf(L"The Doc [%ls] Error: %d\n", input_file, error_code);
    return 1;
  }

  FSDK_PDFDoc_HasLayer(doc, &has_layer);
  FSDK_LayerTree_Create(doc, &layertree);
  FSDK_PDFDoc_HasLayer(doc, &has_layer);
  FSDK_LayerTree_GetRootNode(layertree, &root);

  FSDK_LayerNode_GetChildrenCount(root, &child_count);
  FSDK_LayerNode_AddChild(root, 0, L"AddedLayerNode", TRUE, &return_addchild);
  FSDK_LayerNode_AddChild(root, 0, L"AddedNode", FALSE, &return_addchild);

  swprintf_s(file_info, MAX_FILE_PATH, L"%lscreate_layer_informations.txt", output_directory);
  _wfopen_s(&file, file_info, L"w+");

  GetAllLayerNodesInformation(root, -1, file);
  swprintf_s(output_file, MAX_FILE_PATH, L"%lscreate_layer_tree.pdf", output_directory);
  error_code = FSDK_PDFDoc_SaveAs(doc, output_file, e_FSSaveFlagNoOriginal, &return_result);
  if (error_code != e_FSErrSuccess) {
    printf("Save doc error!\n");
    FSDK_PDFDoc_Release(doc);
    return 1;
  }
  FSDK_LayerTree_Release(layertree);
  layertree = 0;
  FSDK_PDFDoc_Release(doc);

  //Copy graphics objects from A PDF to B PDF
  error_code = FSDK_PDFDoc_Create0(input_file, &doc);
  if (error_code != e_FSErrSuccess) return 1;
  error_code = FSDK_PDFDoc_Load(doc, NULL);
  if (error_code != e_FSErrSuccess) {
    FSDK_PDFDoc_Release(doc);
    wprintf(L"The Doc [%ls] Error: %d\n", input_file, error_code);
    return 1;
  }

  FSDK_PDFDoc_GetPage(doc, 0, &page);

  FSDK_PDFPage_StartParse(page, 0, NULL, FALSE, &progressive);

  swprintf_s(input_file_path, MAX_FILE_PATH, L"%lsSamplePDF.pdf", input_path);

  error_code = FSDK_PDFDoc_Create0(input_file_path, &newdoc);
  if (error_code != e_FSErrSuccess) return 1;
  error_code = FSDK_PDFDoc_Load(newdoc, NULL);
  if (error_code != e_FSErrSuccess) {
    FSDK_PDFDoc_Release(newdoc);
    wprintf(L"The Doc [%ls] Error: %d\n", input_file_path, error_code);
    return 1;
  }

  FSDK_PDFDoc_GetPage(newdoc, 0, &newpage);
  FSDK_PDFPage_StartParse(newpage, 0, NULL, FALSE, &progressive);
  FSDK_PDFDoc_HasLayer(newdoc, &has_layer);
  FSDK_LayerTree_Create(newdoc, &layertree);
  FSDK_PDFDoc_HasLayer(newdoc, &has_layer);
  FSDK_LayerTree_GetRootNode(layertree, &root);
  FSDK_LayerNode_AddChild(root, 0, L"AddedLayerNode", TRUE, &return_addchild);

  for (i = 0; i < 5; i++) {
    FS_POSITION pos = NULL;
    FS_GRAPHICSOBJECT_HANDLE graphics_object = NULL;
    FS_GRAPHICSOBJECT_HANDLE ngraphics_object = NULL;

    FSDK_GraphicsObjects_GetGraphicsObject0(page, i, &graphics_object);

    FSDK_GraphicsObject_Clone(graphics_object, &ngraphics_object);
    FSDK_GraphicsObjects_InsertGraphicsObject(newpage, 0, ngraphics_object, &pos);
    FSDK_LayerNode_AddGraphicsObject(return_addchild, newpage, ngraphics_object, &return_value);
  }
  FSDK_GraphicsObjects_GenerateContent(newpage, &return_value);
  swprintf_s(output_file, MAX_FILE_PATH, L"%lscopy_graphics_objects.pdf", output_directory);

  error_code = FSDK_PDFDoc_SaveAs(newdoc, output_file, e_FSSaveFlagsSaveFlagNormal, &return_result);
  if (error_code != e_FSErrSuccess) {
    printf("Save doc error!\n");
    FSDK_PDFDoc_Release(doc);
    FSDK_PDFDoc_Release(newdoc);
    return 1;
  }
  FSDK_LayerTree_Release(layertree);
  FSDK_PDFDoc_Release(doc);
  FSDK_PDFDoc_Release(newdoc);

  FSDK_Library_Release();
  printf("PDFLayer test.\n");
  return 0;
}
