I need to fill pdf form. To do this I found and use qPDF c++ library.
I added libqpdf.dll.a on fillPdf.pro using :
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll INCLUDEPATH += $$PWD/qpdf DEPENDPATH += $$PWD/qpdf
I also added all includes .h and .hh headers from qpdf library to my project.
But I still have bugs that look like linkage problems :
.o:-1: In function `ZN8reporter8fillTestEPKcS1_S1_': .cpp:19: erreur : undefined reference to `QPDF::QPDF()' .cpp:20: erreur : undefined reference to `QPDF::processFile(char const*, char const*)' ^ .cpp:19: erreur : undefined reference to `QPDF::~QPDF()' collect2.exe:-1: erreur : error: ld returned 1 exit status
summarised code all symbols are recognised by qt creator and i have access to theire classes by clicking on them :
#include <qpdf/QPDF.hh> #include <qpdf/QPDFWriter.hh> #include <qpdf/QUtil.hh> #include <iostream> int main(int argc, char* argv[]) { char* whoami = QUtil::getWhoami(argv[0]); if (argc != 3) { std::cerr << "Usage: " << whoami << " infile outfile" << std::endl; return 2; } char const* infile = argv[1]; char const* outfile = argv[2]; QPDF in; in.processFile(infile); int pageno = 0; std::vector<QPDFObjectHandle> const& pages = in.getAllPages(); for (std::vector<QPDFObjectHandle>::const_iterator iter = pages.begin(); iter != pages.end(); ++iter) { std::cout << ++pageno << " "; QPDFObjectHandle page = *iter; page.replaceKey( "/Contents", QPDFObjectHandle::newStream(&in, "q Q")); } QPDFWriter out(in, outfile); out.write(); return 0; }
More information :
QPDF WINDOWS Lib : https://sourceforge.net/projects/qpdf/files/qpdf/8.4.0/ includes : https://github.com/qpdf/qpdf/tree/master/include/qpdf exemple : https://github.com/qpdf/qpdf/blob/master/examples/pdf-set-form-values.cc
I am using qt creator 4.4.0 based on qt 5.9.1 (MSVC 2015, 32bit)
Can someone tell me where am i wrong?
My .pro
TEMPLATE = app CONFIG += console c++11 CONFIG -= app_bundle CONFIG += qt QT += core gui QT += axcontainer QT += serialport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets SOURCES += main.cpp HEADERS += qpdf/Buffer.hh qpdf/BufferInputSource.hh qpdf/ClosedFileInputSource.hh qpdf/Constants.h qpdf/DLL.h qpdf/FileInputSource.hh qpdf/InputSource.hh qpdf/JSON.hh qpdf/Pipeline.hh qpdf/Pl_Buffer.hh qpdf/Pl_Concatenate.hh qpdf/Pl_Count.hh qpdf/Pl_DCT.hh qpdf/Pl_Discard.hh qpdf/Pl_Flate.hh qpdf/Pl_QPDFTokenizer.hh qpdf/Pl_RunLength.hh qpdf/Pl_StdioFile.hh qpdf/PointerHolder.hh qpdf/qpdf-c.h qpdf/QPDF.hh qpdf/QPDFAcroFormDocumentHelper.hh qpdf/QPDFAnnotationObjectHelper.hh qpdf/QPDFDocumentHelper.hh qpdf/QPDFExc.hh qpdf/QPDFFormFieldObjectHelper.hh qpdf/QPDFNameTreeObjectHelper.hh qpdf/QPDFNumberTreeObjectHelper.hh qpdf/QPDFObject.hh qpdf/QPDFObjectHandle.hh qpdf/QPDFObjectHelper.hh qpdf/QPDFObjGen.hh qpdf/QPDFOutlineDocumentHelper.hh qpdf/QPDFOutlineObjectHelper.hh qpdf/QPDFPageDocumentHelper.hh qpdf/QPDFPageLabelDocumentHelper.hh qpdf/QPDFPageObjectHelper.hh qpdf/QPDFSystemError.hh qpdf/QPDFTokenizer.hh qpdf/QPDFWriter.hh qpdf/QPDFXRefEntry.hh qpdf/QTC.hh qpdf/QUtil.hh qpdf/RandomDataProvider.hh qpdf/Types.h win32:CONFIG(release, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dllINCLUDEPATH += $$PWD/qpdf DEPENDPATH += $$PWD/qpdf
Answer
I get it working using the configuration bellow :
My.pro :
#------------------------------------------------- # # Project created by QtCreator 2019-04-01T16:52:28 # #------------------------------------------------- QT += core gui QT += axcontainer QT += serialport CONFIG += c++11 console CONFIG -= app_bundle greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = QTfillpdftest TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += main.cpp qtfillpdf.cpp HEADERS += qtfillpdf.h qpdf/Buffer.hh qpdf/BufferInputSource.hh qpdf/ClosedFileInputSource.hh qpdf/Constants.h qpdf/DLL.h qpdf/FileInputSource.hh qpdf/InputSource.hh qpdf/JSON.hh qpdf/Pipeline.hh qpdf/Pl_Buffer.hh qpdf/Pl_Concatenate.hh qpdf/Pl_Count.hh qpdf/Pl_DCT.hh qpdf/Pl_Discard.hh qpdf/Pl_Flate.hh qpdf/Pl_QPDFTokenizer.hh qpdf/Pl_RunLength.hh qpdf/Pl_StdioFile.hh qpdf/PointerHolder.hh qpdf/qpdf-c.h qpdf/QPDF.hh qpdf/QPDFAcroFormDocumentHelper.hh qpdf/QPDFAnnotationObjectHelper.hh qpdf/QPDFDocumentHelper.hh qpdf/QPDFExc.hh qpdf/QPDFFormFieldObjectHelper.hh qpdf/QPDFNameTreeObjectHelper.hh qpdf/QPDFNumberTreeObjectHelper.hh qpdf/QPDFObject.hh qpdf/QPDFObjectHandle.hh qpdf/QPDFObjectHelper.hh qpdf/QPDFObjGen.hh qpdf/QPDFOutlineDocumentHelper.hh qpdf/QPDFOutlineObjectHelper.hh qpdf/QPDFPageDocumentHelper.hh qpdf/QPDFPageLabelDocumentHelper.hh qpdf/QPDFPageObjectHelper.hh qpdf/QPDFSystemError.hh qpdf/QPDFTokenizer.hh qpdf/QPDFWriter.hh qpdf/QPDFXRefEntry.hh qpdf/QTC.hh qpdf/QUtil.hh qpdf/RandomDataProvider.hh qpdf/Types.h FORMS += qtfillpdf.ui win32:CONFIG(release, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll else:unix: LIBS += -L$$PWD/qpdf/lib/ -llibqpdf.dll INCLUDEPATH += $$PWD/qpdf DEPENDPATH += $$PWD/qpdf
Function :
int qtfillpdf::qtfillpdfFile( char const* infilename , char const* outfilename,char const* value ) { qDebug() << "qtfillpdf : 1 " << value; // This is a contrived example that just goes through a file page // by page and sets the value of any text fields it finds to a // fixed value as given on the command line. The purpose here is // to illustrate use of the helper classes around interactive // forms. QPDF qpdf; qDebug() << "qtfillpdfFile : 1.1 " << value; qpdf.processFile(infilename); std::string nm; nm= qpdf.getFilename(); qDebug() << "qtfillpdf : 2 " << nm.c_str() ; // We will iterate through form fields by starting at the page // level and looking at each field for each page. We could // also called QPDFAcroFormDocumentHelper::getFormFields to // iterate at the field level, but doing it as below // illustrates how we can map from annotations to fields. QPDFAcroFormDocumentHelper afdh(qpdf); QPDFPageDocumentHelper pdh(qpdf); std::vector<QPDFPageObjectHelper> pages = pdh.getAllPages(); qDebug() << "qtfillpdf : 3 " ; for (std::vector<QPDFPageObjectHelper>::iterator page_iter = pages.begin(); page_iter != pages.end(); ++page_iter) { // Get all widget annotations for each page. Widget // annotations are the ones that contain the details of // what's in a form field. std::vector<QPDFAnnotationObjectHelper> annotations = afdh.getWidgetAnnotationsForPage(*page_iter); for (std::vector<QPDFAnnotationObjectHelper>::iterator annot_iter = annotations.begin(); annot_iter != annotations.end(); ++annot_iter) { // For each annotation, find its associated field. If // it's a text field, set its value. This will // automatically update the document to indicate that // appearance streams need to be regenerated. At the // time of this writing, qpdf doesn't have any helper // code to assist with appearance stream generation, // though there's nothing that prevents it from being // possible. //qDebug() << "qtfillpdf : 4 " << annot_iter->getAppearanceState().c_str() ; QPDFFormFieldObjectHelper ffh = afdh.getFieldForAnnotation(*annot_iter); if (ffh.getFieldType() == "/Tx") { //qDebug() << "qtfillpdf : 5 " <<ffh.getChoices().front().c_str(); // Set the value. This will automatically set // /NeedAppearances to true. If you don't want to // do that, pass false as the second argument. For // details see comments in // QPDFFormFieldObjectHelper.hh. ffh.setV(value); qDebug() << "OK6" << value << " ffh.getValueAsString() : " <<ffh.getValueAsString().c_str(); } } } // Write out a new file QPDFWriter w(qpdf, outfilename); w.setStaticID(true); // for testing only w.write(); return 3; } void qtfillpdf::on_Browse_clicked() { ///TODO : mettre le liens QString s_configFileName; QString outfilename = "OUT.pdf"; QString value="qfiller"; s_configFileName = QFileDialog::getOpenFileName( this, tr("Selectfile"), "", tr("pdf Files (*.pdf)") ); qDebug() << "File Name : " << s_configFileName ; qtfillpdfFile(s_configFileName.toStdString().c_str(), outfilename.toStdString().c_str(), value.toStdString().c_str()); qDebug()<< " END_BROWSE :" << s_configFileName ; }