对比 (Comparison)
对比功能可以帮助用户查看两个版本的 PDF 文档之间的差异。福昕 PDF SDK 提供 APIs 用以逐页比较两个 PDF 文档,并返回文档间的差异。
差异可以定义为三种类型:删除、插入和替换。您可以将这些差异保存为 PDF 文件并标记为注释。
授权说明
- 要使用对比功能,请确保授权许可文件中包含
Comparison
模块权限。
对比两个 PDF 文档,并将差异保存到一个 PDF 文件中
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("@foxitsoftware/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);
}
}
}
(以 Java 开发语言为例)
- 对于
CreateDeleteTextStamp
,CreateDeleteText
和CreateSquigglyRect
函数,请参考 SDK 包中\examples\simple_demo
文件夹下的 "pdfcompare" demo。