// 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 reflow PDF pages.

#include <time.h>
#include<direct.h>
#include <stdio.h>
#include <math.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_reflowpage_c.h"
#include "../../../include/fs_render_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/";

static const wchar_t* output_directory = L"../output_files/pdfreflow/";

const void SaveBitmap(FS_BITMAP_HANDLE bitmap, int index, const wchar_t* file_name) {
  FSRectF margin;
  FSPointF size;
  FSRectI rect;
  FS_IMAGE_HANDLE image = NULL;
  FS_BOOL return_value;
  wchar_t save_path[MAX_FILE_PATH] = { 0 };

  margin.left = 50;
  margin.bottom = 30;
  margin.right = 30;
  margin.top = 30;

  size.x = 480;
  size.y = 800;

  rect.left = 0;
  rect.bottom = 0;
  rect.right = (int)size.x;
  rect.top = (int)margin.top;
  FSDK_Bitmap_FillRect(bitmap, 0xFFFFFFFF, &rect);
  rect.left = 0;
  rect.bottom = (int)(size.y - margin.bottom);
  rect.right = (int)size.x;
  rect.top = (int)size.y;
  FSDK_Bitmap_FillRect(bitmap, 0xFFFFFFFF, &rect);

  FSDK_Image_Create(&image);

  FSDK_Image_AddFrame(image, bitmap, &return_value);

  swprintf_s(save_path, MAX_FILE_PATH, L"%lsreflow%ls%d.bmp", output_directory, file_name, index);

  FSDK_Image_SaveAs(image, save_path, &return_value);
  FSDK_Image_Release(image);
}

// The change for the size of the picture depends on the size of the content of reflow page.
void ReflowSingle(FS_PDFDOC_HANDLE doc) {
  FSRectF margin;
  FSPointF size;
  int page_count, i = 0;

  margin.left = 50;
  margin.bottom = 30;
  margin.right = 30;
  margin.top = 30;

  size.x = 480;
  size.y = 800;

  FSDK_PDFDoc_GetPageCount(doc, &page_count);
  for (i = 0; i < page_count; i++) {
    FS_PDFPAGE_HANDLE page = NULL;
    float content_height;
    float content_width;
    FS_BITMAP_HANDLE bitmap = NULL;
    FS_RENDERER_HANDLE renderer = NULL;
    FSMatrix matrix;
    const wchar_t* file_name = L"_single_";

    FS_PROGRESSIVE_HANDLE progressive = NULL;
    FS_PROGRESSIVE_HANDLE progressive1 = NULL;
    FS_PROGRESSIVE_HANDLE progressive2 = NULL;
    FS_REFLOWPAGE_HANDLE reflow_page = NULL;

    FSDK_PDFDoc_GetPage(doc, i, &page);
    // Parse PDF page.
    FSDK_PDFPage_StartParse(page, e_FSParseFlagsParsePageNormal, NULL, FALSE, &progressive);
    FSDK_ReflowPage_Create(page, &reflow_page);
    // Set some arguments used for parsing the relfow page.
    FSDK_ReflowPage_SetLineSpace(reflow_page, 0);
    FSDK_ReflowPage_SetScreenMargin(reflow_page, (int)margin.left, (int)margin.top,
      (int)margin.right, (int)margin.bottom);
    FSDK_ReflowPage_SetScreenSize(reflow_page, size.x, size.y);
    FSDK_ReflowPage_SetZoom(reflow_page, 100);
    FSDK_ReflowPage_SetParseFlags(reflow_page, e_FSReflowPageFlagsNormal);
    // Parse reflow page.

    FSDK_ReflowPage_StartParse(reflow_page, NULL, &progressive1);

    // Get actual size of content of reflow page. The content size does not contain the margin.
    FSDK_ReflowPage_GetContentHeight(reflow_page, &content_height);

    FSDK_ReflowPage_GetContentWidth(reflow_page, &content_width);

    // Create a bitmap for rendering the reflow page. The bitmap size contains the margin.
    FSDK_Bitmap_Create((int)(content_width + margin.left + margin.right), (int)(content_height + margin.top + margin.bottom), e_FSDIBArgb, NULL, 0, &bitmap);
    FSDK_Bitmap_FillRect(bitmap, 0xFFFFFFFF, NULL);
    // Render reflow page.
    FSDK_Renderer_Create(bitmap, FALSE, &renderer);
    FSDK_ReflowPage_GetDisplayMatrix(reflow_page, 0, 0, (int)content_width, (int)content_height, e_FSRotation0, &matrix);

    FSDK_Renderer_StartRenderReflowPage(renderer, reflow_page, matrix, NULL, &progressive2);
    SaveBitmap(bitmap, i, file_name);

    FSDK_Renderer_Release(renderer);
    FSDK_Bitmap_Release(bitmap);
    FSDK_ReflowPage_Release(reflow_page);
    FSDK_PDFPage_Release(page);
  }
}

// Fixed bitmap size, just to simulate split screen situation.
void ReflowContinuous(FS_PDFDOC_HANDLE doc) {
  FSRectF margin;
  float offset_y = 0;
  int page_count;
  int bitmap_index = 0, i = 0;
  const wchar_t* file_name = L"_continuous_";
  float display_height = 0; 
  FSPointF size;
  FS_BITMAP_HANDLE bitmap = NULL;

  margin.left = 50;
  margin.bottom = 30;
  margin.right = 30;
  margin.top = 30;

  size.x = 480;
  size.y = 800;
  display_height = size.y - margin.top - margin.bottom;

  FSDK_Bitmap_Create((int)size.x, (int)size.y, e_FSDIBArgb, NULL, 0, &bitmap);

  FSDK_PDFDoc_GetPageCount(doc, &page_count);

  for (i = 0; i < page_count; i++) {
    FS_PDFPAGE_HANDLE page = NULL;
    FS_PROGRESSIVE_HANDLE progressive = NULL;
    FS_REFLOWPAGE_HANDLE reflow_page = NULL;
    FS_PROGRESSIVE_HANDLE progressive3 = NULL;
    FS_RENDERER_HANDLE renderer = NULL;
    FS_PROGRESSIVE_HANDLE progressive4 = NULL;

    float content_height;
    float content_width;
    FSMatrix matrix;
    int rate_need_screen_count = 0;

    FSDK_PDFDoc_GetPage(doc, i, &page);

    // Parse PDF page.
    FSDK_PDFPage_StartParse(page, e_FSParseFlagsParsePageNormal, NULL, FALSE, &progressive);
    FSDK_ReflowPage_Create(page, &reflow_page);
    // Set some arguments used for parsing the relfow page.
    FSDK_ReflowPage_SetLineSpace(reflow_page, 0);
    FSDK_ReflowPage_SetScreenMargin(reflow_page, (int)margin.left, (int)margin.top,
      (int)margin.right, (int)margin.bottom);
    FSDK_ReflowPage_SetScreenSize(reflow_page, size.x, size.y);
    FSDK_ReflowPage_SetZoom(reflow_page, 100);
    FSDK_ReflowPage_SetParseFlags(reflow_page, e_FSWithImage);

    FSDK_ReflowPage_SetTopSpace(reflow_page, offset_y);

    // Parse reflow page.
    FSDK_ReflowPage_StartParse(reflow_page, NULL, &progressive3);

    // Get actual size of content of reflow page.
    // The content size does not contain the margin but contains the top space.
    FSDK_ReflowPage_GetContentHeight(reflow_page, &content_height);
    FSDK_ReflowPage_GetContentWidth(reflow_page, &content_width);
    // Render reflow page.
    FSDK_Renderer_Create(bitmap, FALSE, &renderer);

    FSDK_ReflowPage_GetDisplayMatrix(reflow_page, 0, 0, (int)content_width, (int)content_height, e_FSRotation0, &matrix);

    FSDK_Renderer_StartRenderReflowPage(renderer, reflow_page, matrix, NULL, &progressive4);

    rate_need_screen_count = (int)(ceil(max(content_height - display_height, 0.0f) / display_height));
    if (rate_need_screen_count > 0) {
      // Before do next rendering, save current bitmap first.
      const wchar_t* file_name = L"_continuous_";
      float has_display_height = display_height;
      int j = 0;

      SaveBitmap(bitmap, bitmap_index++, file_name);
      for (j = 0; j < rate_need_screen_count; j++) {
        FSMatrix matrix;
        FS_RENDERER_HANDLE renderer = NULL;
        FS_PROGRESSIVE_HANDLE progressive = NULL;

        // Clear the bitmap and used it to do next rendering.
        FSDK_Bitmap_FillRect(bitmap, 0xFFFFFFFF, NULL);
        // Render reflow page.
        FSDK_Renderer_Create(bitmap, FALSE, &renderer);
        FSDK_ReflowPage_GetDisplayMatrix(reflow_page, 0, -has_display_height, (int)content_width, (int)content_height, e_FSRotation0, &matrix);

        FSDK_Renderer_StartRenderReflowPage(renderer, reflow_page, matrix, NULL, &progressive);
        if (j != rate_need_screen_count - 1) {
          has_display_height += display_height;
          SaveBitmap(bitmap, bitmap_index++, file_name);
        } else {
          offset_y = content_height - rate_need_screen_count * display_height;
        }
      }
    } else {
      offset_y = content_height;
    }

    FSDK_ReflowPage_Release(reflow_page);
    FSDK_Renderer_Release(renderer);
    FSDK_PDFPage_Release(page);
  }
  SaveBitmap(bitmap, bitmap_index++, file_name);
  FSDK_Bitmap_Release(bitmap);
}

int main(int argc, char *argv[]) {
  int err_ret = 0;
  FSErrorCode error_code = e_FSErrSuccess;
  FS_PDFDOC_HANDLE doc = NULL;
  wchar_t input_file[MAX_FILE_PATH] = { 0 };

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

  swprintf_s(input_file, MAX_FILE_PATH, L"%lsAboutFoxit.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;
  }
  ReflowContinuous(doc);
  ReflowSingle(doc);

  FSDK_PDFDoc_Release(doc);
  printf("Reflow test.\n");

  return err_ret;
}

