Comparison
The comparison feature helps users see differences between two versions of a PDF document. Foxit PDF SDK provides APIs to compare two PDF documents page by page and return the differences.
Differences can be classified as delete, insert, or replace. You can save these differences to a PDF file and mark them as annotations.
Licensing
- To use comparison, ensure your license includes the
Comparisonmodule.
Compare two PDF documents and save differences to a PDF file
c++
#include "include/common/fs_common.h"
#include "include/pdf/fs_pdfdoc.h"
#include "include/pdf/fs_pdfpage.h"
#include "include/pdf/fs_search.h"
#include "include/addon/fs_compare.h"
#include "include/common/fxcrt/fx_basic.h"
using namespace foxit;
using namespace common;
using namespace addon;
using namespace pdf;
using namespace foxit::pdf::annots;
...
PDFDoc base_doc("input_base_file");
ErrorCode error_code = base_doc.Load();
if (error_code != foxit::e_ErrSuccess) {
return 1;
}
PDFDoc compared_doc("input_compared_file");
error_code = compared_doc.Load();
if (error_code != foxit::e_ErrSuccess) {
return 1;
}
Comparison comparison(base_doc, compared_doc);
// Start comparing.
CompareResults result = comparison.DoCompare(0, 0, Comparison::e_CompareTypeText);
CompareResultInfoArray& oldInfo = result.results_base_doc;
CompareResultInfoArray& newInfo = result.results_compared_doc;
int oldInfoSize = oldInfo.GetSize();
int newInfoSize = newInfo.GetSize();
PDFPage page = compared_doc.GetPage(0);
for (int i=0; i<newInfoSize; i++)
{
const CompareResultInfo& item = newInfo.GetAt(i);
CompareResultInfo::CompareResultType type = item.type;
if (type ompareResultInfo::e_CompareResultTypeDeleteText)
{
String res_string;
res_string.Format((FX_LPCSTR)"\"%s\"", (FX_LPCSTR)String::FromUnicode(item.diff_contents));
CreateDeleteTextStamp(page, item.rect_array, 0xff0000, WString::FromLocal(res_string), L"Compare : Delete", L"Text");
}
else if (type ompareResultInfo::e_CompareResultTypeInsertText)
{
String res_string;
res_string.Format((FX_LPCSTR)"\"%s\"", (FX_LPCSTR)String::FromUnicode(item.diff_contents));
CreateDeleteText(page, item.rect_array, 0x0000ff, WString::FromLocal(res_string), L"Compare : Insert", L"Text");
}
else if (type ompareResultInfo::e_CompareResultTypeReplaceText)
{
String res_string;
res_string.Format("[Old]: \"%s\"\r\n[New]: \"%s\"", (FX_LPCSTR)String::FromUnicode(old_info.GetAt(i).diff_contents), (FX_LPCSTR)String::FromUnicode(item.diff_contents));
CreateSquigglyRect(page, item.rect_array, 0xe7651a, WString::FromLocal(res_string), L"Compare : Replace", L"Text");
}
}
// Save the comparison result to a PDF file.
compared_doc.SaveAs(output_directory + L"result.pdf");C
#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_search_c.h"
#include "include/fs_compare_c.h"
#include "include/fx_basic_c.h"
...
FS_PDFDOC_HANDLE base_doc;
FSDK_PDFDoc_Create0(input_base_file, &base_doc);
FSErrorCode error_code = FSDK_PDFDoc_Load(base_doc, NULL);
if (error_code != e_FSErrSuccess) {
FSDK_PDFDoc_Release(base_doc);
return 1;
}
FS_PDFDOC_HANDLE compared_doc;
FSDK_PDFDoc_Create0(input_compared_file, &compared_doc);
error_code = FSDK_PDFDoc_Load(compared_doc, NULL);
if (error_code != foxit::e_ErrSuccess) {
FSDK_PDFDoc_Release(compared_doc);
return 1;
}
FS_COMPARISON_HANDLE comparison;
FSDK_Comparison_Create(base_doc, compared_doc, &comparison);
// Start comparing.
FSCompareResults result;
result.base_doc_results_array = NULL;
result.compared_doc_results_array = NULL;
FSDK_Comparison_DoCompare(comparison, 0, 0, e_FSCompareTypeText, &result);
result.base_doc_results_array = malloc(sizeof(FSCompareResultInfo) * result.base_doc_results_array_length);
for (int i = 0; i < result.base_doc_results_array_length; i++)
result.base_doc_results_array[i].rect_array = NULL;
result.compared_doc_results_array = malloc( sizeof(FSCompareResultInfo) * result.compared_doc_results_array_length);
for (int i = 0; i < result.compared_doc_results_array_length; i++)
result.compared_doc_results_array[i].rect_array = NULL;
FSDK_Comparison_DoCompare(comparison, 0, 0, e_FSCompareTypeText, &result);
for (int i = 0; i < result.base_doc_results_array_length; i++)
result.base_doc_results_array = malloc(sizeof(FSCompareResultInfo) * result.compared_doc_results_array[i].array_length_rect_array);
for (int i = 0; i < result.compared_doc_results_array_length; i++)
result. compared_doc_results_array[i].rect_array = malloc(sizeof(FSCompareResultInfo) * result.base_doc_results_array_length);
FSDK_Comparison_DoCompare(comparison, 0, 0, e_FSCompareTypeText, &result);
FS_PDFPAGE_HANDLE page;
FSDK_PDFDoc_GetPage(compared_doc, 0, &page);
for (int i=0; i<result.compared_doc_results_array_length; i++)
{
const FSCompareResultInfo item = result.compared_doc_results_array[i];
FSCompareResultType type = item.type;
if (type == e_FSCompareResultTypeDeleteText)
{
wchar_t res_string_new[100];
swprintf_s(res_string_new, L"\"%ls\"", item.diff_contents.str);
/ Add stamp to mark the "delete" type differences between the two documents.
CreateDeleteTextStamp(page, item.rect_array, item.array_length_rect_array, 0xff0000, res_string_new, L"Compare : Delete", L"Text");
}
else if (type == e_FSCompareResultTypeInsertText)
{
wchar_t res_string_new[100];
swprintf_s(res_string_new, 100, L"\"%ls\"", item.diff_contents.str);
/ Highlight the "insert" type differences between the two documents.
CreateDeleteText(page, item.rect_array, item.array_length_rect_array, 0x0000ff, res_string_new, L"Compare : Insert", L"Text");
}
else if (type == e_FSCompareResultTypeReplaceText)
{
wchar_t res_string_new[100];
swprintf_s(res_string_new, 100, "[Old]: \"%s\"\r\n[New]: \"%s\"", result.base_doc_results_array[i].diff_contents.str, item.diff_contents.str);
/ Squiggly the "replace" type differences between the two documents.
CreateSquigglyRect(page, item.rect_array, item.array_length_rect_array, 0xe7651a, res_string_new, L"Compare : Replace", L"Text");
}
}
// Save the comparison result to a PDF file.
FS_BOOL return_result = false;
wchar_t output_compared_doc[MAX_FILE_PATH];
swprintf_s(output_compared_doc, MAX_FILE_PATH, L"%lsnew.pdf", output_directory); FSDK_PDFDoc_SaveAs(compared_doc, output_compared_doc, e_FSSaveFlagsSaveFlagNormal, &return_result);java
import com.foxit.sdk.common.fxcrt.RectF;
import com.foxit.sdk.common.fxcrt.PointF;
import com.foxit.sdk.common.fxcrt.RectFArray;
import com.foxit.sdk.common.Image;
import com.foxit.sdk.pdf.PDFDoc;
import com.foxit.sdk.pdf.PDFPage;
import com.foxit.sdk.addon.comparison.CompareResultInfo;
import com.foxit.sdk.addon.comparison.CompareResultInfoArray;
import com.foxit.sdk.addon.comparison.CompareResults;
import com.foxit.sdk.addon.comparison.Comparison;
import com.foxit.sdk.common.DateTime;
import com.foxit.sdk.pdf.annots.Annot;
import com.foxit.sdk.pdf.annots.Highlight;
import com.foxit.sdk.pdf.annots.Stamp;
import com.foxit.sdk.pdf.annots.QuadPoints;
import com.foxit.sdk.pdf.annots.QuadPointsArray;
...
PDFDoc base_doc = new PDFDoc("input_base_file");
error_code = base_doc.load(null);
if (error_code != e_ErrSuccess) {
return;
}
PDFDoc compared_doc = new PDFDoc("input_compared_file");
error_code = compared_doc.load(null);
if (error_code != e_ErrSuccess) {
return;
}
Comparison comparison = new Comparison(base_doc, compared_doc);
// Start comparing.
CompareResults result = comparison.doCompare(0, 0, Comparison.e_CompareTypeText);
CompareResultInfoArray oldInfo = result.getResults_base_doc();
CompareResultInfoArray newInfo = result.getResults_compared_doc();
long oldInfoSize = oldInfo.getSize();
long newInfoSize = newInfo.getSize();
PDFPage page = compared_doc.getPage(0);
for (int i=0; i<newInfoSize; i++)
{
CompareResultInfo item = newInfo.getAt(i);
int type = item.getType();
if (type ompareResultInfo.e_CompareResultTypeDeleteText)
{
String res_string;
res_string = String.format("\"%s\"", item.getDiff_contents());
CreateDeleteTextStamp(page, item.getRect_array(), 0xff0000, res_string, "Compare : Delete", "Text");
}
else if (type ompareResultInfo.e_CompareResultTypeInsertText)
{
String res_string;
res_string = String.format("\"%s\"", item.getDiff_contents());
CreateDeleteText(page, item.getRect_array(), 0x0000ff, res_string, "Compare : Insert", "Text");
}
else if (type ompareResultInfo.e_CompareResultTypeReplaceText)
{
String res_string;
res_string = String.format("[Old]: \"%s\"\r\n[New]: \"%s\"", oldInfo.getAt(i).getDiff_contents(), item.getDiff_contents());
CreateSquigglyRect(page, item.getRect_array(), 0xe7651a, res_string, "Compare : Replace", "Text");
}
}
// Save the comparison result to a PDF file.
compared_doc.saveAs(output_path + "result.pdf", PDFDoc.e_SaveFlagNormal);py
import sys
import site
if sys.version_info.major == 2:
_PYTHON2_ = True
else:
_PYTHON2_ = False
if _PYTHON2_:
# replace with the python2 lib path
site.addsitedir(‘../../../’)
from FoxitPDFSDKPython2 import *
else:
from FoxitPDFSDKPython3 import *
...
base_doc = PDFDoc(input_base_file)
error_code = base_doc.Load("")
if error_code != e_ErrSuccess:
print("The Doc [{}] Error: {}\n".format(input_base_file, error_code))
return 1
compared_doc = PDFDoc(input_compared_file)
error_code = compared_doc.Load("")
if error_code != e_ErrSuccess:
print("The Doc [{}] Error: {}\n".format(input_base_file, error_code))
return 1
comparison = Comparison(base_doc, compared_doc)
result = comparison.DoCompare(0, 0, Comparison.e_CompareTypeText)
oldInfo = result.base_doc_results
newInfo = result.compared_doc_results
oldInfoSize = oldInfo.GetSize()
newInfoSize = newInfo.GetSize()
page = compared_doc.GetPage(0)
for i in range(0, newInfoSize):
item = newInfo.GetAt(i)
type = item.type
if type ompareResultInfo.e_CompareResultTypeDeleteText:
res_string = "\"{}\"".format(item.diff_contents)
CreateDeleteTextStamp(page, item.rect_array, 0xff0000,
res_string, "Compare : Delete", "Text")
elif type ompareResultInfo.e_CompareResultTypeInsertText:
res_string = "\"{}\"".format(item.diff_contents)
CreateDeleteText(page, item.rect_array, 0x0000ff, res_string,
"Compare : Insert", "Text")
elif type ompareResultInfo.e_CompareResultTypeReplaceText:
res_string = "[Old]: \"{}\"\r\n[New]: \"{}\"".format(
oldInfo.GetAt(i).diff_contents, item.diff_contents)
CreateSquigglyRect(page, item.rect_array, 0xe7651a, res_string,
"Compare : Replace", "Text")
# Save the comparison result to a PDF file.
compared_doc.SaveAs(output_directory + "result.pdf")objc
#include "FSPDFObjC.h"
...
FSPDFDoc *base_doc = [[FSPDFDoc alloc] initWithPath:@"input_base_file"];
errorCode = [base_doc load:@""];
if (errorCode != FSErrSuccess) {
return -1;
}
FSPDFDoc *compared_doc = [[FSPDFDoc alloc] initWithPath:@"input_compared_file"];
errorCode = [compared_doc load:@""];
if (errorCode != FSErrSuccess) {
return -1;
}
FSComparison* comparison = [[FSComparison alloc] initWithBase_doc:base_doc compared_doc:compared_doc];
// Start comparison.
FSCompareResults* result = [comparison doCompare:0 compared_page_index:0 compare_flags:FSComparisonCompareTypeText];
int oldInfoSize = [result.results_base_doc getSize];
int newInfoSize = [result.results_compared_doc getSize];
FSPDFPage* page = [compared_doc getPage:0];
for (int i=0; i<newInfoSize; i++)
{
FSCompareResultInfo* item = [result.results_compared_doc getAt:i];
FSCompareResultInfoCompareResultType type = item.type;
if (type == FSCompareResultInfoCompareResultTypeDeleteText)
{
NSString* res_string = [NSString stringWithFormat:@"\"%@\"", item.diff_contents];
createDeleteTextStamp(page, item.rect_array, 0xff0000, res_string, @"Compare : Delete", @"Text");
}
else if (type == FSCompareResultInfoCompareResultTypeInsertText)
{
NSString* res_string = [NSString stringWithFormat:@"\"%@\"", item.diff_contents];
CreateDeleteText(page, item.rect_array, 0x0000ff, res_string, @"Compare : Insert", @"Text");
}
else if (type == FSCompareResultInfoCompareResultTypeReplaceText)
{
NSString* res_string = [NSString stringWithFormat:@"[Old]: \"%@\"\r\n[New]: \"%@\"",[result.results_base_doc getAt:i].diff_contents,item.diff_contents];
createSquigglyRect(page, item.rect_array, 0xe7651a, res_string, @"Compare : Replace", @"Text");
}
}
// Save the comparison result to a PDF file.
[compared_doc saveAs:[output_directory stringByAppendingString:@"result.pdf"] save_flags:FSPDFDocSaveFlagNormal];js
const FSDK = require("@fuxinsoft/foxit-pdf-sdk-node");
...
let base_doc = new FSDK.PDFDoc(input_base_file);
let error_code = base_doc.Load("");
if (error_code != FSDK.e_ErrSuccess) {
console.log("The Doc [%s] Error: %d\n", input_base_file, error_code);
return 1;
}
let compared_doc = new FSDK.PDFDoc(input_compared_file);
error_code = compared_doc.Load("");
if (error_code != FSDK.e_ErrSuccess) {
console.log("The Doc [%s] Error: %d\n", input_compared_file, error_code);
return 1;
}
let comparison = new FSDK.Comparison(base_doc, compared_doc);
let result = comparison.DoCompare(0, 0, FSDK.Comparison.e_CompareTypeText);
let old_info = result.base_doc_results;
let new_info = result.compared_doc_results;
let = result.compared_doc_results;
let old_info_size = old_info.GetSize();
let new_info_size = new_info.GetSize();
let page_base = base_doc.GetPage(0);
let page = compared_doc.GetPage(0);
for (let i=0; i<new_info_size; i++) {
let item = new_info.GetAt(i);
let type = item.type;
if (type == FSDK.CompareResultInfo.e_CompareResultTypeDeleteText) {
let res_string = `\"${item.diff_contents}\"`;
CreateDeleteTextStamp(page, item.rect_array, 0xff0000, res_string, "Compare : Delete", "Text");
} else if (type == FSDK.CompareResultInfo.e_CompareResultTypeInsertText) {
let res_string = `\"${item.diff_contents}\"`;
CreateDeleteText(page, item.rect_array, 0x0000ff, res_string, "Compare : Insert", "Text");
} else if (type == FSDK.CompareResultInfo.e_CompareResultTypeReplaceText) {
let res_string = `[New]: \"${new_info.GetAt(i).diff_contents}\"\r\n[Old]: \"${item.diff_contents}\"`;
CreateSquigglyRect(page, item.rect_array, 0xe7651a, res_string, "Compare : Replace", "Text");
}
}
// Save the comparison result to a PDF file.
compared_doc.SaveAs(output_directory + "new.pdf", FSDK.PDFDoc.e_SaveFlagNormal);csharp
using foxit;
using foxit.common;
using foxit.common.fxcrt;
using foxit.pdf;
using foxit.pdf.annots;
using foxit.addon;
...
using (PDFDoc base_doc = new PDFDoc("input_base_file"))
{
error_code = base_doc.Load(null);
if (error_code != ErrorCode.e_ErrSuccess)
{
Library.Release();
return;
}
using (PDFDoc compared_doc = new PDFDoc("input_compared_file"))
{
error_code = compared_doc.Load(null);
if (error_code != ErrorCode.e_ErrSuccess)
{
Library.Release();
return;
}
using (Comparison comparison = new Comparison(base_doc, compared_doc))
{
/ Start comparing.
CompareResults result = comparison.DoCompare(0, 0, (int)Comparison.CompareType.e_CompareTypeText);
CompareResultInfoArray oldInfo = result.results_base_doc;
CompareResultInfoArray newInfo = result.results_compared_doc;
uint oldInfoSize = oldInfo.GetSize();
uint newInfoSize = newInfo.GetSize();
using (PDFPage page = compared_doc.GetPage(0))
{
for (uint i = 0; i < newInfoSize; i++)
{
CompareResultInfo item = newInfo.GetAt(i);
CompareResultInfo.CompareResultType type = item.type;
if (type ompareResultInfo.CompareResultType.e_CompareResultTypeDeleteText)
{
String res_string = String.Format("\"{0}\"", item.diff_contents);
CreateDeleteTextStamp(page, item.rect_array, 0xff0000, res_string, "Compare : Delete", "Text");
}
else if (type ompareResultInfo.CompareResultType.e_CompareResultTypeInsertText)
{
String res_string = String.Format("\"{0}\"", item.diff_contents);
CreateDeleteText(page, item.rect_array, 0x0000ff, res_string, "Compare : Insert", "Text");
}
else if (type ompareResultInfo.CompareResultType.e_CompareResultTypeReplaceText)
{
String res_string = String.Format("[Old]: \"{0}\"\r\n[New]: \"{1}\"", oldInfo.GetAt(i).diff_contents, item.diff_contents);
CreateSquigglyRect(page, item.rect_array, 0xe7651a, res_string, "Compare : Replace", "Text");
}
}
}
/ Save the comparison result to a PDF file.
compared_doc.SaveAs(output_path + "result.pdf", (int)PDFDoc.SaveFlags.e_SaveFlagNormal);
}
}
}go
import (
."foxit.com/fsdk"
)
...
base_doc := NewPDFDoc(input_base_file)
error_code := base_doc.Load("")
if error_code != E_ErrSuccess{
fmt.Printf("The Doc [%s] Error: %d\n",input_base_file, error_code)
return 1
}
compared_doc := NewPDFDoc(input_compared_file)
error_code = compared_doc.Load("")
if error_code != E_ErrSuccess{
fmt.Printf("The Doc [%s] Error: %d\n",input_base_file, error_code)
return 1
}
comparison := NewComparison(base_doc, compared_doc)
result := comparison.DoCompare(0, 0, ComparisonE_CompareTypeText)
oldInfo := result.GetBase_doc_results()
newInfo := result.GetCompared_doc_results()
oldInfoSize := oldInfo.GetSize()
newInfoSize := newInfo.GetSize()
page := compared_doc.GetPage(0)
for i :=0; i<newInfoSize;i++{
item := newInfo.GetAt(i)
type := item.GetType()
if type == CompareResultInfoE_CompareResultTypeDeleteText{
res_string := fmt.Sprintf("\"%s\"", item.GetDiff_contents())
CreateDeleteTextStamp(page, item.GetRect_array(), 0xff0000,
res_string, "Compare : Delete", "Text")
}
else if type == CompareResultInfoE_CompareResultTypeInsertText{
res_string := fmt.Sprintf("\"%s\"", item.GetDiff_contents())
CreateDeleteText(page, item.GetRect_array(), 0x0000ff, res_string,
"Compare : Insert", "Text")
}
else if type == CompareResultInfoE_CompareResultTypeReplaceText{
res_string := fmt.Sprintf("[New]: \"%s\"\r\n[Old]: \"%s\"",
newInfo.GetAt(int64(i)).GetDiff_contents(), item.GetDiff_contents())
CreateSquigglyRect(page, item.GetRect_array(), 0xe7651a, res_string,
"Compare : Replace", "Text")
}
}
# Save the comparison result to a PDF file.
compared_doc.SaveAs(output_directory + "result.pdf")NOTE
- For
CreateDeleteTextStamp,CreateDeleteText, andCreateSquigglyRect, see the "pdfcompare" demo in the\examples\simple_demofolder in the SDK package.