// 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 Conversion 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 add various annotations to PDF document.

const FSDK = require("@foxitsoftware/foxit-pdf-sdk-node");
const fs = require('fs');
const os = require('os');
const path = require('path');

var sn = "bPxThFlBAYifO3yiW0C51bKbjPap1zHaf5aG5sX378TjFvB7Q0802A==";
var 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";

const input_path = "../input_files/";
const output_path = "../output_files/";
const output_directory = path.join(output_path, 'annotation/');

class IconProviderCallback {
  constructor(file_folder) {
    this.file_folder_ = file_folder;
    this.pdf_doc_map_ = new Map();
    this.icon_names_ = [];
    this.use_dynamic_stamp_ = false;
  }

  SetUseDynamicStamp(use_dynamic_stamp) {    
    this.use_dynamic_stamp_ = use_dynamic_stamp;
  }

  Release() {    
  }

  GetProviderID() {
    if (this.use_dynamic_stamp_)
      return "Simple Demo Dynamic IconProvider";
    else
      return "Simple Demo IconProvider";
  }

  GetProviderVersion() {
    return "1.0.0";
  }

  HasIcon(annot_type, icon_name) {    
    const it = this.pdf_doc_map_.get(icon_name);
    if (it !== undefined) {
      const doc = it;
      return !doc.IsEmpty();
    }
    let doc = new FSDK.PDFDoc();
    let path = '';
    if (doc.GetPageCount() === 0) {
      try {
        if (this.use_dynamic_stamp_) {
          path = `${this.file_folder_}/DynamicStamps/${icon_name}.pdf`;
        } else {
          path = `${this.file_folder_}/StaticStamps/${icon_name}.pdf`;
        }
        doc = new FSDK.PDFDoc(path);
        const errorCode = doc.Load("");

        if (errorCode !== FSDK.e_ErrSuccess) {
          doc = new FSDK.PDFDoc();
        } else {
          this.pdf_doc_map_.set(path, doc);
        }
      } catch (e) {
        console.log(e.message);
      }
    }    
    return !doc.IsEmpty();
  }

  CanChangeColor(annot_type, icon_name) {
    return false;
  }

  GetIcon(annot_type, icon_name, color, annot_dict) {
    const path = this.use_dynamic_stamp_? `${this.file_folder_}/DynamicStamps/${icon_name}.pdf` : `${this.file_folder_}/StaticStamps/${icon_name}.pdf`;    
    const doc = this.pdf_doc_map_.has(path) ? this.pdf_doc_map_.get(path) : new FSDK.PDFDoc();
    if (doc.IsEmpty() || doc.GetPageCount() === 0) {
      return new FSDK.PDFPage();
    }
    return doc.GetPage(0);
  }

  GetShadingColor(annot_type, icon_name, referenced_color, out_shading_color) {
    return false;
  }

  GetDisplayWidth(annot_type, icon_name) {
    return 0.0;
  }

  GetDisplayHeight(annot_type, icon_name) {
    return 0.0;
  }
}

class ActionEventCallback {
  constructor(document) {
    this.current_doc_ = document;
  }
  Release() {}

  InvalidateRect(document, page_index, pdf_rect) {
    return false
  }

  GetCurrentPage(document) {
    return -1;
  }

  SetCurrentPage(document, page_index) {}

  SetCurrentPage(document, destination){}

  GetPageRotation(document, page_index) {
    return FSDK.e_Rotation0;
  }

  SetPageRotation(document, page_index, rotation) {
    return false;
  }

  ExecuteNamedAction(document, named_action) {
    return false;
  }

  SetDocChangeMark(document, change_mark) {
    return false;
  }

  GetDocChangeMark(document) {
    return false;
  }

  GetOpenedDocCount() {
    return -1;
  }

  GetOpenedDoc(index) {
    return this.current_doc_;
  }

  GetCurrentDoc() {
    return this.current_doc_;
  }

  CreateBlankDoc() {
    return new FSDK.PDFDoc();
  }

  OpenDoc(file_path, password) {
    return new FSDK.PDFDoc(file_path);
  }

  CloseDoc(document, is_prompt_to_save) {}

  Beep(type) {
    return false;
  }

  Response(question, title, default_value, label, is_password) {
      return "";
  }

  GetFilePath(document) {    
    return "";
  }

  IsLocalFile(document) { return true; }
  Print(document, is_ui,page_set, is_silent ,
    is_shrunk_to_fit, is_printed_as_image,
    is_reversed, is_to_print_annots) {
      return false;
  }
  Print(document, print_params) { return false; }
  SubmitForm(document, form_data, length, url, file_format_type) {
    return false;
  }
  LaunchURL(url) {
    return false;
  }
  BrowseFile() {
    return "";
  }
  BrowseFile(is_open_dialog, file_format, file_filter) {
    return "";
  }
  GetLanguage() {
    return FSDK.ActionCallback.e_LanguageCHS;
  }
  Alert(msg, title, type, icon) {
    return 0;
  }
  GetIdentityProperties() {
    return new FSDK.IdentityProperties("foxitsoftware", "simple_demo@foxitsoftware.cn", "simple demo", "Simple", "simple", "demo", "developer", "gsdk");
  }
  SetIdentityProperties(identity_properties) {
    return false;
  }
  PopupMenu(menus, is_selected_item) {
    return "";
  }

  PopupMenuEx(menus, is_selected_item)
  {
    return new FSDK.MenuItemEx();
  }

  GetAppInfo(type) {
    return "";
  }
  MailData(data, data_type, is_ui, to,
    subject, cc, bcc, message) {
      return false;
  }
  MailDoc(document, to_address, cc_address, 
      bcc_address, subject, message, is_ui) {
    return FSDK.JsMailResult.e_JSMailResultFailed;
  }
  VerifySignature(document, pdf_signature) {
    return FSDK.Signature.e_StateUnknown;
  }
  GetUntitledBookmarkName() { return "Untitled"; }

  GetPrinterNameList() {
    return FSDK.WStringArray();
  }

  AddToolButton(button_item) { return false; }
  RemoveToolButtom(button_name) { return false; }
  GetMenuItemNameList() { return new FSDK.MenuListArray(); }
  AddSubMenu(menu_item_config) { return false; }
  AddMenuItem(menu_item_config, is_prepend) { return false; }
  ShowDialog(dlg_config) { return true; }
  GetFullScreen() { return false; }
  SetFullScreen(is_full_screen) {}
  OnFieldValueChanged(field_name, type, value_before_changed, value_after_changed) {}
  OpenMediaPlayer(player_args) { return NULL; }
  GetAttachmentsFilePath(pdf_doc, name) { return ""; }
  GetExtractedEmbeddedFilePath(pdf_doc, name) { return ""; }
  UpdateLogicalLabel() {}
  GetTemporaryFileName(document, file_name) { return ""; }
  GetTemporaryDirectory() { return ""; }
  Scroll(point) {}
  SelectPageNthWord(page_index, start_offset, end_offset, is_show_selection) {}
  GetMousePosition() { return new FSDK.PointF(); }
  GetPageWindowRect(pdf_doc, page_index) { return new FSDK.RectF(); }
  GetLayoutMode() { return FSDK.LayoutMode.e_LayoutModeContinuous; }
  SetLayoutMode(layout_mode, is_cover_mode) {}
  GetPageScale() { return 0; }
  SetPageScale(zoom_mode, dest) {}
  GetPageZoomMode() { return FSDK.Destination.e_ZoomFitBHorz; }
  Query(keywords, search_scope, search_option, di_path) {}
  AddSearchIndex(di_path, is_selected) { return FSDK.SearchIndexConfig(); }
  RemoveSearchIndex(search_index_config) { return false; }
  GetSignatureAPStyleNameList() { return new FSDK.WStringArray(); }
  SoapRequest(request_params) {return new FSDK.SOAPResponseInfo();}
  EnablePageLoop(is_loop) {}
  IsPageLoop() {return true;}
  SetDefaultPageTransitionMode(trans_type, trans_di) {}
  IsCurrentDocOpenedInBrowser() { return false; }
  PostMessageToHtml(message) {}
  NotifyBeginDoJob(pdf_doc, event_type) {}
  NotifyAfterDataChange(pdf_doc,modify_item_info) {}
  NotifyEndDoJob(pdf_doc, event_type) {}
  InitModifyItem(pdf_doc, item_type, page_index, dict_name) { return false; }
  ResetModifyItem(pdf_doc) {}
  GetVisiblePageCount(pdf_doc) { return 0;}
  GetVisiblePage(pdf_doc, page_index) { return -1;}
}



function RandomUID() {
  const characters = "0123456789qwertyuiopasdfghjklzxcvbnm";
  let uuid = "";

  for (let n = 0; n < 16; n++) {
    let uuidTemp = "";
    const b = Math.floor(Math.random() * 255);

    switch (n) {
      case 6:
        uuidTemp = '4' + (b % 15).toString(16);
        break;
      case 8:
        const randomCharIndex = Math.floor(Math.random() * characters.length);
        uuidTemp = characters[randomCharIndex] + (b % 15).toString(16);
        break;
      default:
        let hex = b.toString(16);
        if (hex.length < 2) {
          hex = '0' + hex;
        }
        uuidTemp = hex;
        break;
    }

    uuid += uuidTemp;
    if (n === 3 || n === 5 || n === 7 || n === 9) {
      uuid += '-';
    }
  }
  return uuid;
}

// get current date time
function GetLocalDateTime() {
  const date = new Date();
  let timezone_hour = date.getTimezoneOffset() / 60 * -1;
  let timezone_minute = Math.abs(date.getTimezoneOffset() % 60);
  let datetime = new FSDK.DateTime(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds(), timezone_hour, timezone_minute);
  return datetime;
}

function AddAnnotations(page) {
  let line = new FSDK.Line(page.AddAnnot(FSDK.Annot.e_Line, new FSDK.RectF(0,650,100,750)));
  //This flag is used for printing annotations.
  line.SetFlags(4);
  line.SetStartPoint(new FSDK.PointF(20,650));
  line.SetEndPoint(new FSDK.PointF(100,740));
  // Intent, as line arrow.
  line.SetContent("A line arrow annotation");
  line.SetIntent("LineArrow");
  line.SetSubject("Arrow");
  line.SetTitle("Foxit SDK");
  line.SetCreationDateTime(GetLocalDateTime());
  line.SetModifiedDateTime(GetLocalDateTime());
  line.SetUniqueID(RandomUID());
  // Appearance should be reset.
  line.ResetAppearanceStream();

  line = new FSDK.Line(page.AddAnnot(FSDK.Annot.e_Line, new FSDK.RectF(0,650,100,760)));
  //This flag is used for printing annotations.
  line.SetFlags(4);
  // Set foxit RGB color
  line.SetBorderColor(0x00FF00);
  line.SetStartPoint(new FSDK.PointF(10,650));
  line.SetEndPoint(new FSDK.PointF(100,750));  
  line.SetContent("A common line");
  line.SetLineStartStyle(FSDK.Markup.e_EndingStyleSquare);
  line.SetLineEndStyle(FSDK.Markup.e_EndingStyleOpenArrow);
  line.SetSubject("Arrow");
  line.SetTitle("Foxit SDK");
  line.SetCreationDateTime(GetLocalDateTime());
  line.SetModifiedDateTime(GetLocalDateTime());
  line.SetUniqueID(RandomUID());
  line.EnableCaption(true);
  // Appearance should be reset.
  line.ResetAppearanceStream();
  console.log("Add a line annotations.");

  let circle = new FSDK.Circle(page.AddAnnot(FSDK.Annot.e_Circle, new FSDK.RectF(100, 650, 200, 750)));
  //This flag is used for printing annotations.
  circle.SetFlags(4);
  circle.SetInnerRect(new FSDK.RectF(120,660,160,740));
  circle.SetSubject("Circle");
  circle.SetTitle("Foxit SDK");
  circle.SetCreationDateTime(GetLocalDateTime());
  circle.SetModifiedDateTime(GetLocalDateTime());
  circle.SetUniqueID(RandomUID());
  // Appearance should be reset.
  circle.ResetAppearanceStream();
  console.log("Add a circle annotation.");
  
  // Add square annotation
  let square = new FSDK.Square(page.AddAnnot(FSDK.Annot.e_Square, new FSDK.RectF(200,650,300,750)));
  //This flag is used for printing annotations.
  square.SetFlags(4);
  square.SetFillColor(0x00FF00);
  square.SetInnerRect(new FSDK.RectF(220,660,260,740));
  square.SetSubject("Square");
  square.SetTitle("Foxit SDK");
  square.SetCreationDateTime(GetLocalDateTime());
  square.SetModifiedDateTime(GetLocalDateTime());
  square.SetUniqueID(RandomUID());
  // Appearance should be reset.
  square.ResetAppearanceStream();
  console.log("Add a square annotation.");

  // Add polygon annotation, as cloud.
  let polygon = new FSDK.Polygon(page.AddAnnot(FSDK.Annot.e_Polygon,new FSDK.RectF(300,650,500,750)));
  //This flag is used for printing annotations.
  polygon.SetFlags(4);
  polygon.SetIntent("PolygonCloud");
  polygon.SetFillColor(0x0000FF);
  let vertexe_array = new FSDK.PointFArray();
  vertexe_array.Add(new FSDK.PointF(335,665));
  vertexe_array.Add(new FSDK.PointF(365,665));
  vertexe_array.Add(new FSDK.PointF(385,705));
  vertexe_array.Add(new FSDK.PointF(365,740));
  vertexe_array.Add(new FSDK.PointF(335,740));
  vertexe_array.Add(new FSDK.PointF(315,705));
  polygon.SetVertexes(vertexe_array);
  polygon.SetSubject("Cloud");
  polygon.SetTitle("Foxit SDK");
  polygon.SetCreationDateTime(GetLocalDateTime());
  polygon.SetModifiedDateTime(GetLocalDateTime());
  polygon.SetUniqueID(RandomUID());
  // Appearance should be reset.
  polygon.ResetAppearanceStream();
  console.log("Add a polygon annotation.");


  // Add polygon annotation, with dashed border.
  let borderinfo = new FSDK.BorderInfo()
  borderinfo.cloud_intensity = 2.0;
  borderinfo.width = 2.0;
  borderinfo.style = FSDK.BorderInfo.e_Dashed;
  borderinfo.dash_phase = 3.0;
  borderinfo.dashes.SetSize(2.0, -1);
  borderinfo.dashes.SetAt(0,2);
  borderinfo.dashes.SetAt(1,2);

  polygon = new FSDK.Polygon(page.AddAnnot(FSDK.Annot.e_Polygon,new FSDK.RectF(400,650,500,750)));
  //This flag is used for printing annotations.
  polygon.SetFlags(4);
  polygon.SetFillColor(0x0000FF);
  polygon.SetBorderInfo(borderinfo);
  vertexe_array = new FSDK.PointFArray();
  vertexe_array.Add(new FSDK.PointF(435,665));
  vertexe_array.Add(new FSDK.PointF(465,665));
  vertexe_array.Add(new FSDK.PointF(485,705));
  vertexe_array.Add(new FSDK.PointF(465,740));
  vertexe_array.Add(new FSDK.PointF(435,740));
  vertexe_array.Add(new FSDK.PointF(415,705));

  polygon.SetVertexes(vertexe_array);
  polygon.SetSubject("Polygon");
  polygon.SetTitle("Foxit SDK");
  polygon.SetCreationDateTime(GetLocalDateTime());
  polygon.SetModifiedDateTime(GetLocalDateTime());
  polygon.SetUniqueID(RandomUID());
  // Appearance should be reset.
  polygon.ResetAppearanceStream();
  console.log("Add a polygon cloud annotation.");


  // Add polyline annotation
  let polyline = new FSDK.PolyLine(page.AddAnnot(FSDK.Annot.e_PolyLine, new FSDK.RectF(500,650,600,700)));
  //This flag is used for printing annotations.
  polyline.SetFlags(4);
  vertexe_array = new FSDK.PointFArray();
  vertexe_array.Add(new FSDK.PointF(515,705));
  vertexe_array.Add(new FSDK.PointF(535,740));
  vertexe_array.Add(new FSDK.PointF(565,740));
  vertexe_array.Add(new FSDK.PointF(585,705));
  vertexe_array.Add(new FSDK.PointF(565,665));
  vertexe_array.Add(new FSDK.PointF(535,665));
  polyline.SetVertexes(vertexe_array);
  polyline.SetSubject("PolyLine");
  polyline.SetTitle("Foxit SDK");
  polyline.SetCreationDateTime(GetLocalDateTime());
  polyline.SetModifiedDateTime(GetLocalDateTime());
  polyline.SetUniqueID(RandomUID());
  // Appearance should be reset.
  polyline.ResetAppearanceStream();
  console.log("Add a polyline annotation.");

  // Add freetext annotation, as type writer.
  let freetext = new FSDK.FreeText(page.AddAnnot(FSDK.Annot.e_FreeText, new FSDK.RectF(10,550,200,600)));
  //This flag is used for printing annotations.
  freetext.SetFlags(4);
  // Set default appearance
  let default_ap = new FSDK.DefaultAppearance();
  default_ap.flags = FSDK.DefaultAppearance.e_FlagFont | FSDK.DefaultAppearance.e_FlagFontSize | FSDK.DefaultAppearance.e_FlagTextColor;
  default_ap.font = new FSDK.Font(FSDK.Font.e_StdIDHelvetica);
  default_ap.text_size = 12.0;
  default_ap.text_color = 0x000000;
  // Set default appearance for form.
  freetext.SetDefaultAppearance(default_ap);
  freetext.SetIntent("FreeTextTypewriter");
  freetext.SetContent("A typewriter annotation");
  freetext.SetSubject("FreeTextTypewriter");
  freetext.SetTitle("Foxit SDK");
  freetext.SetCreationDateTime(GetLocalDateTime());
  freetext.SetModifiedDateTime(GetLocalDateTime());
  freetext.SetUniqueID(RandomUID());
  // Appearance should be reset.
  freetext.ResetAppearanceStream();
  console.log("Add a typewriter freetext annotation.")

  // Add freetext annotation, as call-out.
  freetext = new FSDK.FreeText(page.AddAnnot(FSDK.Annot.e_FreeText, new FSDK.RectF(300,550,400,600)));
  //This flag is used for printing annotations.
  freetext.SetFlags(4);
  // Set default appearance
  default_ap = new FSDK.DefaultAppearance();
  default_ap.flags = FSDK.DefaultAppearance.e_FlagFont | FSDK.DefaultAppearance.e_FlagFontSize | FSDK.DefaultAppearance.e_FlagTextColor;
  default_ap.font = new FSDK.Font(FSDK.Font.e_StdIDHelveticaB);
  default_ap.text_size = 12.0;
  default_ap.text_color = 0x000000;
  // Set default appearance for form.
  freetext.SetDefaultAppearance(default_ap);
  freetext.SetIntent("FreeTextCallout");
  let callout_points = new FSDK.PointFArray();
  callout_points.Add(new FSDK.PointF(250,540));
  callout_points.Add(new FSDK.PointF(280,570));
  callout_points.Add(new FSDK.PointF(300,570));

  freetext.SetCalloutLinePoints(callout_points);
  freetext.SetCalloutLineEndingStyle(FSDK.Markup.e_EndingStyleOpenArrow);
  freetext.SetContent("A callout annotation.");
  freetext.SetSubject("FreeTextCallout");
  freetext.SetTitle("Foxit SDK");
  freetext.SetCreationDateTime(GetLocalDateTime());
  freetext.SetModifiedDateTime(GetLocalDateTime());
  freetext.SetUniqueID(RandomUID());
  // Appearance should be reset.
  freetext.ResetAppearanceStream();
  console.log("Add a callout freetext annotation.")

  // Add freetext annotation, as text box.
  freetext = new FSDK.FreeText(page.AddAnnot(FSDK.Annot.e_FreeText,new FSDK.RectF(450,550,550,600)));
  //This flag is used for printing annotations.
  freetext.SetFlags(4);
  // Set default appearance
  default_ap = new FSDK.DefaultAppearance();
  default_ap.flags = FSDK.DefaultAppearance.e_FlagFont | FSDK.DefaultAppearance.e_FlagFontSize | FSDK.DefaultAppearance.e_FlagTextColor;
  default_ap.font = new FSDK.Font(FSDK.Font.e_StdIDHelveticaI);
  default_ap.text_size = 12.0;
  default_ap.text_color = 0x000000;
  // Set default appearance for form.
  freetext.SetDefaultAppearance(default_ap);
  freetext.SetContent("A text box annotation.");
  freetext.SetSubject("Textbox");
  freetext.SetTitle("Foxit SDK");
  freetext.SetCreationDateTime(GetLocalDateTime());
  freetext.SetModifiedDateTime(GetLocalDateTime());
  freetext.SetUniqueID(RandomUID());
  // Appearance should be reset.
  freetext.ResetAppearanceStream();
  console.log("Add a text box freetext annotation.");

  
  // Add highlight annotation.
  let highlight= new FSDK.Highlight(page.AddAnnot(FSDK.Annot.e_Highlight, new FSDK.RectF(10,450,100,550)));
  //This flag is used for printing annotations.
  highlight.SetFlags(4);
  highlight.SetContent("Highlight");
  let quad_points = new FSDK.QuadPoints();
  quad_points.first = new FSDK.PointF(10, 500);
  quad_points.second = new FSDK.PointF(90, 500);
  quad_points.third = new FSDK.PointF(10, 480);
  quad_points.fourth = new FSDK.PointF(90, 480);
  let quad_points_array = new FSDK.QuadPointsArray();
  quad_points_array.Add(quad_points);
  highlight.SetQuadPoints(quad_points_array);
  highlight.SetSubject("Highlight");
  highlight.SetTitle("Foxit SDK");
  highlight.SetCreationDateTime(GetLocalDateTime());
  highlight.SetModifiedDateTime(GetLocalDateTime());
  highlight.SetUniqueID(RandomUID());
  // Appearance should be reset.
  highlight.ResetAppearanceStream();
  console.log("Add a highlight annotation.");


  // Add underline annotation.
  underline = new FSDK.Underline(page.AddAnnot(FSDK.Annot.e_Underline, new FSDK.RectF(100,450,200,550)));
  //This flag is used for printing annotations.
  underline.SetFlags(4);
  quad_points = new FSDK.QuadPoints();
  quad_points.first = new FSDK.PointF(110, 500);
  quad_points.second = new FSDK.PointF(190, 500);
  quad_points.third = new FSDK.PointF(110, 480);
  quad_points.fourth = new FSDK.PointF(190, 480);
  quad_points_array = new FSDK.QuadPointsArray();
  quad_points_array.Add(quad_points);
  underline.SetQuadPoints(quad_points_array);
  underline.SetSubject("Underline");
  underline.SetTitle("Foxit SDK");
  underline.SetCreationDateTime(GetLocalDateTime());
  underline.SetModifiedDateTime(GetLocalDateTime());
  underline.SetUniqueID(RandomUID());
  // Appearance should be reset.
  underline.ResetAppearanceStream();
  console.log("Add a underline annotation.");


  // Add squiggly annotation.
  let squiggly = new FSDK.Squiggly(page.AddAnnot(FSDK.Annot.e_Squiggly, new FSDK.RectF(200,450,300,550)));
  //This flag is used for printing annotations.
  squiggly.SetFlags(4);
  squiggly.SetIntent("Squiggly");

  quad_points = new FSDK.QuadPoints();
  quad_points.first = new FSDK.PointF(210, 500);
  quad_points.second = new FSDK.PointF(290, 500);
  quad_points.third = new FSDK.PointF(210, 480);
  quad_points.fourth = new FSDK.PointF(290, 480);
  quad_points_array = new FSDK.QuadPointsArray();
  quad_points_array.Add(quad_points);
  squiggly.SetQuadPoints(quad_points_array);
  squiggly.SetSubject("Squiggly");
  squiggly.SetTitle("Foxit SDK");
  squiggly.SetCreationDateTime(GetLocalDateTime());
  squiggly.SetModifiedDateTime(GetLocalDateTime());
  squiggly.SetUniqueID(RandomUID());
  // Appearance should be reset.
  squiggly.ResetAppearanceStream();
  console.log("Add a squiggly annotation.");

  // Add strikeout annotation.
  let strikeout= new FSDK.StrikeOut(page.AddAnnot(FSDK.Annot.e_StrikeOut, new FSDK.RectF(300,450,400,550)));
  //This flag is used for printing annotations.
  strikeout.SetFlags(4);
  quad_points = new FSDK.QuadPoints();
  quad_points.first = new FSDK.PointF(310, 500);
  quad_points.second = new FSDK.PointF(390, 500);
  quad_points.third = new FSDK.PointF(310, 480);
  quad_points.fourth = new FSDK.PointF(390, 480);
  quad_points_array = new FSDK.QuadPointsArray ;
  quad_points_array.Add(quad_points);
  strikeout.SetQuadPoints(quad_points_array);
  strikeout.SetSubject("StrikeOut");
  strikeout.SetTitle("Foxit SDK");
  strikeout.SetCreationDateTime(GetLocalDateTime());
  strikeout.SetModifiedDateTime(GetLocalDateTime());
  strikeout.SetUniqueID(RandomUID());
  // Appearance should be reset.
  strikeout.ResetAppearanceStream();
  console.log("Add a strikeout annotation.");

  // Add caret annotation.
  let caret = new FSDK.Caret(page.AddAnnot(FSDK.Annot.e_Caret, new FSDK.RectF(400,450,420,470)));
  //This flag is used for printing annotations.
  caret.SetFlags(4);
  caret.SetInnerRect(new FSDK.RectF(410,450,430,470));
  caret.SetContent("Caret annotation");
  caret.SetSubject("Caret");
  caret.SetTitle("Foxit SDK");
  caret.SetCreationDateTime(GetLocalDateTime());
  caret.SetModifiedDateTime(GetLocalDateTime());
  caret.SetUniqueID(RandomUID());
  // Appearance should be reset.
  caret.ResetAppearanceStream();
  console.log("Add a caret annotation.");

  // Add note annotation
  let note = new FSDK.Note(page.AddAnnot(FSDK.Annot.e_Note, new FSDK.RectF(10,350,50,400)));
  //This flag is used for printing annotations.
  note.SetFlags(4);
  note.SetIconName("Comment");
  note.SetSubject("Note");
  note.SetTitle("Foxit SDK");
  note.SetContent("Note annotation.");
  note.SetCreationDateTime(GetLocalDateTime());
  note.SetModifiedDateTime(GetLocalDateTime());
  note.SetUniqueID(RandomUID());
  // Add popup to note annotation
  let popup = new FSDK.Popup(page.AddAnnot(FSDK.Annot.e_Popup, new FSDK.RectF(300,450,500,550)));
  popup.SetBorderColor(0x00FF00);
  popup.SetOpenStatus(false);
  popup.SetModifiedDateTime(GetLocalDateTime());
  note.SetPopup(popup);

  // Add reply annotation to note annotation
  let reply = note.AddReply();
  reply.SetContent("reply");
  reply.SetModifiedDateTime(GetLocalDateTime());
  reply.SetTitle("Foxit SDK");
  reply.SetUniqueID(RandomUID());

  // Add state annotation to note annotation
  let state = note.AddStateAnnot("Foxit SDK", FSDK.Markup.e_StateModelReview, FSDK.Markup.e_StateAccepted);  
  state.SetContent("Accepted set by Foxit SDK");
  state.SetUniqueID(RandomUID());
  // Appearance should be reset.
  note.ResetAppearanceStream();
  console.log("Add a note annotation.");

  // Add ink annotation
  let ink = new FSDK.Ink(page.AddAnnot(FSDK.Annot.e_Ink, new FSDK.RectF(100,350,200,450)));
  //This flag is used for printing annotations.
  ink.SetFlags(4);
  inklist = new FSDK.Path();
  let width = 100.0;
  let height = 100.0;
  let out_width = Math.min(width, height) * 2 / 3.0;
  let inner_width = out_width * Math.sin(18.0 / 180.0 * 3.14) / Math.sin(36.0 / 180.0 * 3.14);
  let center = new FSDK.PointF(150, 400);
  let x = out_width;
  let y = 0.0;
  inklist.MoveTo(new FSDK.PointF(center.x + x, center.y + y));
  for (let i = 0; i < 5; i++) {
    x = out_width * Math.cos(72.0 * i / 180.0 * 3.14);
    y = out_width * Math.sin(72.0 * i / 180.0 * 3.14);
    inklist.LineTo(new FSDK.PointF(center.x + x, center.y + y));

    x = inner_width * Math.cos((72.0 * i + 36) / 180.0 * 3.14);
    y = inner_width * Math.sin((72.0 * i + 36) / 180.0 * 3.14);
    inklist.LineTo(new FSDK.PointF(center.x + x, center.y + y));
  }
  inklist.LineTo(new FSDK.PointF(center.x + out_width, center.y + 0));
  inklist.CloseFigure();
  ink.SetInkList(inklist);
  ink.SetSubject("Ink");
  ink.SetTitle("Foxit SDK");
  ink.SetContent("Note annotation.");
  ink.SetCreationDateTime(GetLocalDateTime());
  ink.SetModifiedDateTime(GetLocalDateTime());
  ink.SetUniqueID(RandomUID());
  // Appearance should be reset.
  ink.ResetAppearanceStream();
  console.log("Add an ink annotation.");


  // Add file attachment annotation
  let pdf_file = input_path + "AboutFoxit.pdf";
  let file_attachment = new FSDK.FileAttachment(page.AddAnnot(FSDK.Annot.e_FileAttachment, new FSDK.RectF(280,350,300,380)));
  //This flag is used for printing annotations.
  file_attachment.SetFlags(4);
  file_attachment.SetIconName("Graph");

  let file_spec = new FSDK.FileSpec(page.GetDocument());
  file_spec.SetFileName("attachment.pdf");
  file_spec.SetCreationDateTime(GetLocalDateTime());
  file_spec.SetDescription("The original file");
  file_spec.SetModifiedDateTime(GetLocalDateTime());
  file_spec.Embed(pdf_file);
  file_attachment.SetFileSpec(file_spec);
  file_attachment.SetSubject("File Attachment");
  file_attachment.SetTitle("Foxit SDK");
  // Appearance should be reset.
  file_attachment.ResetAppearanceStream();
  console.log("Add an attachment annotation.");


  // Add link annotation
  let link = new FSDK.Link(page.AddAnnot(FSDK.Annot.e_Link, new FSDK.RectF(350,350,380,400)));
  //This flag is used for printing annotations.
  link.SetFlags(4);
  link.SetHighlightingMode(FSDK.Annot.e_HighlightingPush);

  // Add action for link annotation
  let action = new FSDK.URIAction(FSDK.Action.Create(page.GetDocument(), FSDK.Action.e_TypeURI));
  action.SetTrackPositionFlag(true);
  action.SetURI("www.foxitsoftware.com");
  link.SetAction(action);
  // Appearance should be reset.
  link.ResetAppearanceStream();
  console.log("Add a link annotation.")

  const icon_provider_callback = new IconProviderCallback("../input_files/Stamps");
  // Set icon provider for annotation to Foxit PDF SDK.
  let icon_provider = new FSDK.IconProviderCallback(icon_provider_callback);
  icon_provider_callback.SetUseDynamicStamp(false);
  FSDK.Library.SetAnnotIconProviderCallback(icon_provider);

  // Add common stamp annotation.
  FSDK.Library.SetActionCallback(null);
  let static_stamp = new FSDK.Stamp(page.AddAnnot(FSDK.Annot.e_Stamp, new FSDK.RectF(110,150,200,250)));
  //This flag is used for printing annotations.
  static_stamp.SetFlags(4);
  static_stamp.SetIconName("Approved");
  // Appearance should be reset.
  static_stamp.ResetAppearanceStream();

  // // Add dynamic stamp annotation.
  let action_event_callback = new ActionEventCallback(page.GetDocument());
  let action_callback = new FSDK.ActionCallback(action_event_callback);
  FSDK.Library.SetActionCallback(action_callback);
  icon_provider_callback.SetUseDynamicStamp(true);
  let dynamic_stamp = new FSDK.Stamp(page.AddAnnot(FSDK.Annot.e_Stamp, new FSDK.RectF(10,150,100,250)));
  //This flag is used for printing annotations.
  dynamic_stamp.SetFlags(4);
  dynamic_stamp.SetIconName("Approved");
  // Appearance should be reset.
  dynamic_stamp.ResetAppearanceStream();
  console.log("Add stamp annotations.");


  // Add freetext annotation with richtext, as type writer.
  freetext = new FSDK.FreeText(page.AddAnnot(FSDK.Annot.e_FreeText, new FSDK.RectF(10, 50, 200, 100)));
  //This flag is used for printing annotations.
  freetext.SetFlags(4);
  // Set default appearance
  default_ap = new FSDK.DefaultAppearance();
  default_ap.flags = FSDK.DefaultAppearance.e_FlagFont | FSDK.DefaultAppearance.e_FlagFontSize | FSDK.DefaultAppearance.e_FlagTextColor;
  default_ap.font = new FSDK.Font(FSDK.Font.e_StdIDHelvetica);
  default_ap.text_size = 12.0;
  default_ap.text_color = 0x000000;
  // Set default appearance for form.
  freetext.SetDefaultAppearance(default_ap);
  freetext.SetIntent("FreeTextTypewriter");
  freetext.SetContent("A typewriter annotation");
  freetext.SetSubject("FreeTextTypewriter");
  freetext.SetTitle("Foxit SDK");
  freetext.SetCreationDateTime(GetLocalDateTime());
  freetext.SetModifiedDateTime(GetLocalDateTime());
  freetext.SetUniqueID(RandomUID());
  let richtext_style = new FSDK.RichTextStyle();

  if (os.platform() === 'linux') {
    richtext_style.font = new FSDK.Font("FreeSerif", 0, FSDK.Font.e_CharsetANSI, 0);
  } else {
    richtext_style.font = new FSDK.Font("Times New Roman", 0, FSDK.Font.e_CharsetANSI, 0);
  }


  richtext_style.text_color = 0xFF0000;
  richtext_style.text_size = 10;
  freetext.AddRichText("Typewriter annotation ", richtext_style);

  richtext_style.text_color = 0x00FF00;
  richtext_style.is_underline = true;
  freetext.AddRichText("1-underline ", richtext_style);

  if (os.platform() === 'linux') {
    richtext_style.font = new FSDK.Font("FreeSans", 0, FSDK.Font.e_CharsetANSI, 0);
  } else {
    richtext_style.font = new FSDK.Font("Calibri", 0, FSDK.Font.e_CharsetANSI, 0);
  }
  
  richtext_style.text_color = 0x0000FF;
  richtext_style.is_underline = false;
  richtext_style.is_strikethrough = true;
  let richtext_count = freetext.GetRichTextCount();
  freetext.InsertRichText(richtext_count-1, "2_strikethrough ", richtext_style);

  // Appearance should be reset.
  freetext.ResetAppearanceStream();
  console.log("Add a typewriter freetext annotation with richtext.");


  // Add freetext annotation with richtext, as call-out.
  freetext = new FSDK.FreeText(page.AddAnnot(FSDK.Annot.e_FreeText, new FSDK.RectF(300, 50, 400, 100)));
  //This flag is used for printing annotations.
  freetext.SetFlags(4);
  // Set default appearance
  default_ap = new FSDK.DefaultAppearance();
  default_ap.flags = FSDK.DefaultAppearance.e_FlagFont | FSDK.DefaultAppearance.e_FlagFontSize | FSDK.DefaultAppearance.e_FlagTextColor;
  default_ap.font = new FSDK.Font(FSDK.Font.e_StdIDHelveticaB);
  default_ap.text_size = 12.0;
  default_ap.text_color = 0x000000;
  // Set default appearance for form.
  freetext.SetDefaultAppearance(default_ap);
  freetext.SetIntent("FreeTextCallout");
  callout_points = new FSDK.PointFArray();
  callout_points.Add(new FSDK.PointF(250, 60));
  callout_points.Add(new FSDK.PointF(280, 80));
  callout_points.Add(new FSDK.PointF(300, 80));

  freetext.SetCalloutLinePoints(callout_points);
  freetext.SetCalloutLineEndingStyle(FSDK.Markup.e_EndingStyleOpenArrow);
  freetext.SetContent("A callout annotation.");
  freetext.SetSubject("FreeTextCallout");
  freetext.SetTitle("Foxit SDK");
  freetext.SetCreationDateTime(GetLocalDateTime());
  freetext.SetModifiedDateTime(GetLocalDateTime());
  freetext.SetUniqueID((RandomUID()));
  richtext_style = new FSDK.RichTextStyle(); 

  if (os.platform() === 'linux') {
    richtext_style.font = new FSDK.Font("FreeSerif", 0, FSDK.Font.e_CharsetANSI, 0);
  } else {
    richtext_style.font = new FSDK.Font("Times New Roman", 0, FSDK.Font.e_CharsetANSI, 0);
  }

  richtext_style.text_color = 0xFF0000;
  richtext_style.text_size = 10;
  freetext.AddRichText("Callout annotation ", richtext_style);

  richtext_style.text_color = 0x00FF00;
  richtext_style.is_underline = true;
  freetext.AddRichText("1-underline ", richtext_style);

  if (os.platform() === 'linux') {
    richtext_style.font = new FSDK.Font("FreeSans", 0, FSDK.Font.e_CharsetANSI, 0);
  } else {
    richtext_style.font = new FSDK.Font("Calibri", 0, FSDK.Font.e_CharsetANSI, 0);
  }

  richtext_style.text_color = 0x0000FF;
  richtext_style.is_underline = false;
  richtext_style.is_strikethrough = true;
  richtext_count = freetext.GetRichTextCount();
  freetext.InsertRichText(richtext_count - 1, "2_strikethrough ", richtext_style);

  // Appearance should be reset.
  freetext.ResetAppearanceStream();
  console.log("Add a callout freetext annotation with richtext.")


  // Add freetext annotation with richtext, as text box.
  freetext = new FSDK.FreeText(page.AddAnnot(FSDK.Annot.e_FreeText, new FSDK.RectF(450, 50, 550, 100)));
  //This flag is used for printing annotations.
  freetext.SetFlags(4);
  // Set default appearance
  default_ap = new FSDK.DefaultAppearance();
  default_ap.flags = FSDK.DefaultAppearance.e_FlagFont | FSDK.DefaultAppearance.e_FlagFontSize | FSDK.DefaultAppearance.e_FlagTextColor;
  default_ap.font = new FSDK.Font(FSDK.Font.e_StdIDHelveticaI);
  default_ap.text_size = 12.0;
  default_ap.text_color = 0x000000;
  // Set default appearance for form.
  freetext.SetDefaultAppearance(default_ap);
  freetext.SetContent("A text box annotation.");
  freetext.SetSubject("Textbox");
  freetext.SetTitle("Foxit SDK");
  freetext.SetCreationDateTime(GetLocalDateTime());
  freetext.SetModifiedDateTime(GetLocalDateTime());
  freetext.SetUniqueID(RandomUID());

  richtext_style = new FSDK.RichTextStyle();


  if (os.platform() === 'linux') {
    richtext_style.font = new FSDK.Font("FreeSerif", 0, FSDK.Font.e_CharsetANSI, 0);
  } else {
    richtext_style.font = new FSDK.Font("Times New Roman", 0, FSDK.Font.e_CharsetANSI, 0);
  }

  richtext_style.text_color = 0xFF0000;
  richtext_style.text_size = 10;
  freetext.AddRichText("Textbox annotation ", richtext_style);

  richtext_style.text_color = 0x00FF00;
  richtext_style.is_underline = true;
  freetext.AddRichText("1-underline ", richtext_style);

  if (os.platform() === 'linux') {
    richtext_style.font = new FSDK.Font("FreeSans", 0, FSDK.Font.e_CharsetANSI, 0);
  } else {
    richtext_style.font = new FSDK.Font("Calibri", 0, FSDK.Font.e_CharsetANSI, 0);
  }

  richtext_style.text_color = 0x0000FF;
  richtext_style.is_underline = false;
  richtext_style.is_strikethrough = true;
  richtext_count = freetext.GetRichTextCount();
  freetext.InsertRichText(richtext_count - 1, "2_strikethrough ", richtext_style);

  // Appearance should be reset.
  freetext.ResetAppearanceStream();
  console.log("Add a text box freetext annotation witch richtext.");

  //Add screen annotation
  let image = new FSDK.Image(input_path+ "FoxitLogo.jpg");
  let screen = new FSDK.Screen(page.AddAnnot(FSDK.Annot.e_Screen, new FSDK.RectF(300, 150, 400, 200)));
  //This flag is used for printing annotations.
  screen.SetFlags(4);
  screen.SetTitle("Foxit SDK");
  screen.SetBorderColor(0x0000FF);
  screen.SetBorderInfo(new FSDK.BorderInfo(2, FSDK.BorderInfo.e_Solid, 0, 0, new FSDK.FloatArray()));
  screen.SetImage(image, 0, 1);

  // Prepare rendition action
  let rendition_action = new FSDK.RenditionAction(FSDK.Action.Create(page.GetDocument(), FSDK.Action.e_TypeRendition));

  rendition_action.SetOperationType(FSDK.RenditionAction.e_OpTypeAssociate);
  rendition_action.SetScreenAnnot(screen);

  // Prepare rendition
  let rendition = new FSDK.Rendition(page.GetDocument(), null);

  rendition.SetRenditionName("screen for rendition");
  rendition.SetMediaClipName("ytb210-Mopa.mp4");
  rendition.SetPermission(FSDK.Rendition.e_MediaPermTempAccess);
  let video_filespec = new FSDK.FileSpec(page.GetDocument());
  video_filespec.SetFileName("ytb210-Mopa.mp4");
  let video_file_path = input_path + "ytb210-Mopa.mp4";

  video_filespec.Embed(video_file_path);
  rendition.SetMediaClipFile(video_filespec);
  rendition.SetMediaClipContentType("video/mp4");
  rendition_action.InsertRendition(rendition, -1);
  screen.SetAction(rendition_action);
  screen.ResetAppearanceStream();
  console.log("Add a screen annotation.");
}

function AddAnnotsWithLowLevelAPI(page) {

  // Add line annotation
  let annot_dict = new FSDK.PDFDictionary.Create();
  annot_dict.SetAtName("Type", "Annot");
  annot_dict.SetAtName("Subtype", "Line");
  annot_dict.SetAtName("IT", "LineArrow");
  annot_dict.SetAtInteger("F", 4);
  annot_dict.SetAtString("Contents", "A line arrow annotation.");
  annot_dict.SetAtString("T", "Foxit SDK");
  annot_dict.SetAtString("Subj", "Arrow");
  annot_dict.SetAtString("NM", RandomUID());
  annot_dict.SetAtDateTime("CreationDate", GetLocalDateTime());
  annot_dict.SetAtDateTime("M", GetLocalDateTime());
  annot_dict.SetAtRect("Rect", new FSDK.RectF(0, 650, 100, 750));
  let coords_array = FSDK.PDFArray.Create();
  coords_array.AddFloat(20.0);
  coords_array.AddFloat(670.0);
  coords_array.AddFloat(80.0);
  coords_array.AddFloat(730.0);
  annot_dict.SetAt("L", coords_array);
  let line_style = FSDK.PDFArray.Create();
  line_style.AddName("None");
  line_style.AddName("OpenArrow");
  annot_dict.SetAt("LE", line_style);
  let border_dict = FSDK.PDFDictionary.Create();
  border_dict.SetAtFloat("W", 2.0);
  border_dict.SetAtName("S", "S");
  border_dict.SetAtName("Type", "Border");
  annot_dict.SetAt("BS", border_dict);
  color_array = FSDK.PDFArray.Create();
  color_array.AddFloat(1);
  color_array.AddFloat(1);
  color_array.AddFloat(0);
  annot_dict.SetAt("C", color_array);
  let annot = page.AddAnnot(annot_dict);
  annot.ResetAppearanceStream();
  console.log("Add a line annotation by lower level API.");

  // Add line annotation with caption
  annot_dict = new FSDK.PDFDictionary.Create();
  annot_dict.SetAtName("Type", "Annot");
  annot_dict.SetAtName("Subtype", "Line");
  annot_dict.SetAtName("IT", "LineArrow");
  annot_dict.SetAtInteger("F", 4);
  annot_dict.SetAtString("Contents", "A common line.");
  annot_dict.SetAtString("T", "Foxit SDK");
  annot_dict.SetAtString("Subj", "Line");
  annot_dict.SetAtString("NM", RandomUID());
  annot_dict.SetAtDateTime("CreationDate", GetLocalDateTime());
  annot_dict.SetAtDateTime("M", GetLocalDateTime());
  annot_dict.SetAtRect("Rect", new FSDK.RectF(0, 650, 100, 750));
  annot_dict.SetAtBoolean("Cap", true);

  var caption_offset = FSDK.PDFArray.Create();
  caption_offset.AddFloat(0);
  caption_offset.AddFloat(5);
  annot_dict.SetAt("CO", caption_offset);
  coords_array = FSDK.PDFArray.Create();
  coords_array.AddFloat(40);
  coords_array.AddFloat(670);
  coords_array.AddFloat(100);
  coords_array.AddFloat(730);
  annot_dict.SetAt("L", coords_array);
  line_style = FSDK.PDFArray.Create();
  line_style.AddName("Square");
  line_style.AddName("OpenArrow");
  annot_dict.SetAt("LE", line_style);
  border_dict = FSDK.PDFDictionary.Create();
  border_dict.SetAtFloat("W", 2.0);
  border_dict.SetAtName("S", "S");
  border_dict.SetAtName("Type", "Border");
  annot_dict.SetAt("BS", border_dict);
  var color_array = FSDK.PDFArray.Create();
  color_array.AddFloat(0);
  color_array.AddFloat(1);
  color_array.AddFloat(0);
  annot_dict.SetAt("C", color_array);
  annot = page.AddAnnot(annot_dict);
  annot.ResetAppearanceStream();
  console.log("Add a line annotation with caption by lower level API.");

  // Add circle annotation
  annot_dict = FSDK.PDFDictionary.Create();
  annot_dict.SetAtName("Type", "Annot");
  annot_dict.SetAtName("Subtype", "Circle");
  annot_dict.SetAtInteger("F", 4);
  annot_dict.SetAtString("T", "Foxit SDK");
  annot_dict.SetAtString("Subj", "Circle");
  annot_dict.SetAtString("NM", RandomUID());
  annot_dict.SetAtDateTime("CreationDate", GetLocalDateTime());
  annot_dict.SetAtDateTime("M", GetLocalDateTime());
  annot_dict.SetAtRect("Rect", new FSDK.RectF(120, 650, 180, 750));

  border_dict = FSDK.PDFDictionary.Create();
  border_dict.SetAtFloat("W", 2.0);
  border_dict.SetAtName("S", "S");
  border_dict.SetAtName("Type", "Border");
  annot_dict.SetAt("BS", border_dict);
  var color_array = FSDK.PDFArray.Create();
  color_array.AddFloat(0);
  color_array.AddFloat(1);
  color_array.AddFloat(0);
  annot_dict.SetAt("C", color_array);
  annot = page.AddAnnot(annot_dict);
  annot.ResetAppearanceStream();
  console.log("Add a circle annotation by lower level API.")

  // Add square annotation
  annot_dict = FSDK.PDFDictionary.Create();
  annot_dict.SetAtName("Type", "Annot");
  annot_dict.SetAtName("Subtype", "Square");
  annot_dict.SetAtInteger("F", 4);
  annot_dict.SetAtString("T", "Foxit SDK");
  annot_dict.SetAtString("Subj", "Square");
  annot_dict.SetAtString("NM", RandomUID());
  annot_dict.SetAtDateTime("CreationDate", GetLocalDateTime());
  annot_dict.SetAtDateTime("M", GetLocalDateTime());
  annot_dict.SetAtRect("Rect", new FSDK.RectF(200, 650, 300, 750));

  border_dict = FSDK.PDFDictionary.Create();
  border_dict.SetAtFloat("W", 2.0);
  border_dict.SetAtName("S", "S");
  border_dict.SetAtName("Type", "Border");
  annot_dict.SetAt("BS", border_dict);
  let interior_color_array = FSDK.PDFArray.Create();
  interior_color_array.AddFloat(1);
  interior_color_array.AddFloat(1);
  interior_color_array.AddFloat(0);
  annot_dict.SetAt("IC", interior_color_array);
  color_array = FSDK.PDFArray.Create();
  color_array.AddFloat(0);
  color_array.AddFloat(1);
  color_array.AddFloat(0);
  annot_dict.SetAt("C", color_array);
  annot = page.AddAnnot(annot_dict);
  annot.ResetAppearanceStream();
  console.log("Add a square annotation by lower level API.");
}


function SaveSoundToFile(sound, file_path) {
  if (sound.IsEmpty()) {
    return false;
  }

  const file = fs.openSync(file_path, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_TRUNC);
  if (!file) {
    return false;
  }

  let sound_stream = sound.GetSoundStream();
  let stream_size = sound_stream.GetDataSize(false)
  let data = sound_stream.GetData(false, stream_size);
  let bit = sound.GetBits();
  const riff_size = stream_size + 36;
  // Write file header
  const wav_file_header = Buffer.alloc(44);
  let i = 0;
  wav_file_header.write('RIFF', i, 4, 'ascii');
  wav_file_header.writeUInt32LE(riff_size, 4);  
  wav_file_header.write('WAVEfmt ', 8, 8, 'ascii');
  wav_file_header.writeUInt32LE(16, 16);
  wav_file_header.writeUInt16LE(1, 20);
  wav_file_header.writeUInt16LE(sound.GetChannelCount(), 22);
  wav_file_header.writeUInt32LE(sound.GetSamplingRate(), 24);
  wav_file_header.writeUInt32LE((sound.GetSamplingRate() * sound.GetChannelCount() * bit) / 8, 28);
  wav_file_header.writeUInt16LE((bit * sound.GetChannelCount()) / 8, 32);
  wav_file_header.writeUInt16LE(bit, 34);
  wav_file_header.write('data', 36, 4, 'ascii');
  wav_file_header.writeUInt32LE(stream_size, 40);
  fs.writeSync(file, wav_file_header, 0, 44);
  // Write file data
  const encoding_format = sound.GetSampleEncodingFormat();
  let buffer;
  switch (encoding_format) {
    case FSDK.Sound.e_SampleEncodingFormatALaw:
      break;
    case FSDK.Sound.e_SampleEncodingFormatMuLaw:
      break;
    case FSDK.Sound.e_SampleEncodingFormatSigned:
      buffer = Buffer.alloc(stream_size + 1);
      let j = 0, k = 0;
      for (let i = 0; i < stream_size; i += 2) {
        let low = data[j++];
        let high;
        if (j === stream_size) {
          high = 0;
        } else {
          high = data[j++];
        }
        buffer[i] = high;
        buffer[i + 1] = low;
      }

      fs.writeSync(file, buffer, 0, stream_size);
      break;
    case FSDK.Sound.e_SampleEncodingFormatRaw:
      default:
        fs.writeSync(file, data, 0, stream_size);
        break;
  }
  fs.closeSync(file);
  return true;
}

function GetAnnotWithType(pdf_page, annot_type, annot_index_with_type, annot_index_with_all)
{
  if (pdf_page.IsEmpty() || annot_type <  - 1) return new FSDK.Annot();

  var ret_annot;
  annot_count = pdf_page.GetAnnotCount();
  var spec_annot_index = -1;
  for (var i = 0; i < annot_count; i++)
  {
    annot_i = pdf_page.GetAnnot(i);
    cmp_index = -1;

    if ( -1 == annot_type)
    {
      cmp_index = i;
    }
    else if (annot_i.GetType() == annot_type)
    {
      spec_annot_index++;
      cmp_index = spec_annot_index;
    }
    if (cmp_index == annot_index_with_type)
    {
      annot_index_with_all = i;
      ret_annot = annot_i;
      break;
    }
  }
  return ret_annot;
}

function GetSoundAnnot(input_pdf_path, page_index)
{
  doc = new FSDK.PDFDoc(input_pdf_path);
  doc.Load("");
  pdf_page = doc.GetPage(page_index);
  if (pdf_page.IsEmpty())
  {
    return null;
  }

  annot_index_with_type = 0;
  annot_index_with_all = 0;
  annot = GetAnnotWithType(pdf_page, FSDK.Annot.e_Sound, annot_index_with_type, annot_index_with_all);
  if (annot.IsEmpty())
  {
    return null;
  }
  if (annot.GetType() != FSDK.Annot.e_Sound)
  {
    return null;
  }

  return new FSDK.Sound(annot);
}

let error_code = FSDK.Library.Initialize(sn, key);
if (FSDK.e_ErrSuccess != error_code) {
  if (FSDK.e_ErrInvalidLicense == error_code)
    console.log("[Failed] Current used Foxit PDF SDK key information is invalid.");
  else
    console.log("Library Initialize Error: %d", FSDK.e_ErrSuccess);
  return;
}
if (!fs.existsSync(output_directory)) {
  fs.mkdirSync(output_directory);
}

try{
  let input_file = input_path + "annotation_input.pdf";
  let output_directory = output_path + "annotation/";
  let doc = new FSDK.PDFDoc(input_file)
  let code = doc.Load("");
  let page = doc.GetPage(0);
  AddAnnotations(page);
  let newPdf = output_directory + "annotation.pdf";
  doc.SaveAs(newPdf, 0);
} catch (e) {
  console.log(e); 
}


try{
  let input_file = input_path + "annotation_input.pdf";
  let output_directory = output_path + "annotation/";
  let doc = new FSDK.PDFDoc(input_file)
  let code = doc.Load("");
  let page = doc.GetPage(0);
  AddAnnotsWithLowLevelAPI(page);
  let newPdf = output_directory + "annotation_lower_level_API.pdf";
  doc.SaveAs(newPdf, 0);
} catch (e) {
  console.log(e); 
}

try{
  //save sound to file:
  let output_sound_file = output_directory + "sound.wav";
  let input_sound_pdf_file = input_path + "sound.pdf";

  let sound = GetSoundAnnot(input_sound_pdf_file, 0);
  if (SaveSoundToFile(sound, output_sound_file))
  {
    console.log("Save sound annotation to file, saved file path:%s", output_sound_file);
  }
} catch (e) {
  console.log(e); 
}


console.log("Annotations demo.");
FSDK.Library.Release();
