/*! ** ** \file pdfToolboxSampleThreadSafe.cpp ** ** \brief multithreaded sample program (OpenMP) ** ** \author © 2013 callas software GmbH, Berlin, Germany - www.callassoftware.com * */ //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #ifndef _WIN32 # include # include # include # include # include # include # include #endif #include #if defined(_WIN32) || defined(_M_X64) # include #elif defined(MAC_ENV) # include "Carbon.h" #endif #include "ptb.h" #define EXIT_WITH_FAILURE 100 typedef std::basic_string TStringUTF8; #include // Locking Stuff // #define USE_OMP_NEST_LOCK 1 #ifdef USE_OMP_NEST_LOCK // note: omp_nest_lock does *not* work together with g++-4.3 on unix (SEGV) # define SAMPLE_LOCK_T omp_nest_lock_t # define SAMPLE_INIT_LOCK omp_init_nest_lock # define SAMPLE_SET_LOCK omp_set_nest_lock # define SAMPLE_UNSET_LOCK omp_unset_nest_lock # define SAMPLE_INIT_LOCK omp_init_nest_lock #else # define SAMPLE_LOCK_T omp_lock_t # define SAMPLE_INIT_LOCK omp_init_lock # define SAMPLE_SET_LOCK omp_set_lock # define SAMPLE_UNSET_LOCK omp_unset_lock # define SAMPLE_INIT_LOCK omp_init_lock #endif SAMPLE_LOCK_T console_lock; // synchronize access to console output SAMPLE_LOCK_T inputqueue_lock; // synchronize access to input queue struct lock_raii_t { lock_raii_t(SAMPLE_LOCK_T &lock_) : lock(lock_) { SAMPLE_SET_LOCK(&lock); } ~lock_raii_t() { SAMPLE_UNSET_LOCK(&lock); } SAMPLE_LOCK_T &lock; }; void init_sample_locks() { # ifdef USE_OMP_NEST_LOCK std::cout << std::endl; std::cout << "**********************************************************************************************************" << std::endl; std::cout << "be aware! omp_nest_lock does not work together with some g++ versions on unix (namely g++-4.3 causes SEGV)" << std::endl; std::cout << "**********************************************************************************************************" << std::endl; # endif SAMPLE_INIT_LOCK(&console_lock); SAMPLE_INIT_LOCK(&inputqueue_lock); } //////////////////////////////////////////////////////////////////////////////// struct CUserdata_t { CUserdata_t(const std::string &inputfile, const PTB_Path_t *outputfile, const std::string &logfile) : inputfile(inputfile), outputfile(outputfile), logfile(logfile) , hits(0), fixups(0), isPDFA(true), idResult(PTB_INVALID_ID), lastValue(0), sindent(0) { logstream.open(logfile.c_str()); } const std::string inputfile; const PTB_Path_t *outputfile; const std::string logfile; unsigned int hits; unsigned int fixups; bool isPDFA; PTB_ResultID idResult; PTB_size_t lastValue; int sindent; ~CUserdata_t() { if (logstream.is_open()) logstream.close(); if (PTB_INVALID_ID != idResult) PTB_PreflightRelease( idResult, NULL ); } void log(const std::string &s) { if (logstream.is_open()) { for (int i=0; i inputfiles; #ifdef _WIN32 bool path_exists(const std::string &filePath, bool want_directory=false) { DWORD fileAtt = GetFileAttributesA(filePath.c_str()); if(fileAtt == INVALID_FILE_ATTRIBUTES) return false; if (want_directory) { return fileAtt & FILE_ATTRIBUTE_DIRECTORY; } return ( fileAtt & FILE_ATTRIBUTE_DIRECTORY ) == 0; } void scan_inputfolder(const std::string &inputfolder) { WIN32_FIND_DATAA FileData; std::string filename(inputfolder); filename += "\\*"; HANDLE hSearch = FindFirstFileA(filename.c_str(), &FileData); if (INVALID_HANDLE_VALUE == hSearch) { std::cout << "failed to open inputfolder " << inputfolder << std::endl; return; } do { std::string path(path_combine(inputfolder, FileData.cFileName)); if (path_exists(path)) { std::cout << "queued " << path << std::endl; inputfiles.push_back(path.c_str()); } } while (FindNextFileA(hSearch, &FileData)); } #else bool path_exists(const std::string &filePath, bool want_directory=false) { struct stat sb; if (lstat(filePath.c_str(), &sb) == -1) { return false; } if (want_directory) { return (sb.st_mode & S_IFMT) == S_IFDIR; } return (sb.st_mode & S_IFMT) == S_IFREG; // regular file } void scan_inputfolder(const std::string &inputfolder) { DIR *dirHandle=opendir(inputfolder.c_str()); if (0==dirHandle) return; struct dirent * dirEntry=0; while(0 != (dirEntry = readdir(dirHandle))) { std::string path(path_combine(inputfolder, dirEntry->d_name)); if (path_exists(path)) { std::cout << "queued " << path << std::endl; inputfiles.push_back(path.c_str()); } } closedir(dirHandle); } #endif //////////////////////////////////////////////////////////////////////////////// /*! Write log statement to console */ template< typename T > void workerConsoleLog( const T & t ) { lock_raii_t lock_(console_lock); std::cout << " worker #" << omp_get_thread_num() << " - " << t << std::endl; } //////////////////////////////////////////////////////////////////////////////// /*! convert a PTB_StringID to a std::string */ std::string getString( PTB_StringID idStr, bool bDispose = false ) { if( PTB_IsValidStringID( idStr ) ) { PTB_size_t size; PTB_EError err = PTB_StringLength( idStr, &size ); if( err != PTB_eerrNone ) { throw std::runtime_error( std::string("call to PTB_StringLength() failed") ); } std::vector< PTB_utf8_char_t > buf( size ); err=PTB_StringGet( idStr, &buf[0], &size ); if( err != PTB_eerrNone ) { throw std::runtime_error( std::string("call to PTB_StringGet() failed") ); } if( bDispose ) { PTB_StringRelease( idStr ); } //remove NULL byte buf.pop_back(); return std::string( buf.begin(), buf.end() ); } else { return ""; } } //////////////////////////////////////////////////////////////////////////////// /*! convert a PTB_EError to a std::string */ std::string getErrorString( const std::string &where, PTB_EError err ) { PTB_StringID strid; PTB_EError err2 = PTB_GetErrorMessage( err, &strid ); if( err2 == PTB_eerrNone ) { std::stringstream ss; ss << where << " failed -> " << getString(strid); return ss.str(); } return ""; } std::string getErrorString( PTB_EError err ) { PTB_StringID strid; PTB_EError err2 = PTB_GetErrorMessage( err, &strid ); if( err2 == PTB_eerrNone ) { return getString(strid); } return ""; } //////////////////////////////////////////////////////////////////////////////// /*! Check for no error */ void require_noErr( PTB_EError err, bool bThrow = false, bool bUseDict = true ) { if (err == PTB_eerrNone) return; std::ostringstream oss; oss << "ERROR: 0x" << std::hex << err; if (err == PTB_eerrKeyCodeFail) oss << " (PTB_eerrKeyCodeFail)"; else if (err == PTB_eerrKeyCodeExpire) oss << "PTB_eerrKeyCodeExpire"; else if (bUseDict) { oss << " (" << getErrorString(err) << ")"; } if( bThrow ) throw std::runtime_error( oss.str() ); else workerConsoleLog(oss.str()); } void require_noErr2( PTB_EError err, CUserdata_t *userData, bool bThrow = false, bool bUseDict = true ) { if( err != PTB_eerrNone ) { std::ostringstream oss; if( bUseDict ) { oss << "ERROR: 0x" << std::hex << err; oss << " (" << getErrorString( err ) << ")" << std::endl; } else { oss << "ERROR: 0x" << std::hex << err << std::endl; } if (userData) userData->log(oss.str()); if( bThrow ) throw std::runtime_error( oss.str() ); else workerConsoleLog(oss.str()); } } static const unsigned int pathBufSize=255; PTB_Path_t *make_ptb_path(const std::string &strSource, PTB_Path_t bufTarget[], unsigned int bufSize=pathBufSize) { require_noErr(PTB_ConvertSysToUTF8(strSource.c_str(), bufTarget, &bufSize)); return bufTarget; } //////////////////////////////////////////////////////////////////////////////// /*! convert a std::string to valid UTF8 string */ TStringUTF8 getUTF8( const std::string& source ) { if( source.empty() ) return TStringUTF8(); std::vector buffer( source.size()+1 ); PTB_size_t size = static_cast( buffer.size() ); const PTB_EError error = PTB_ConvertSysToUTF8( source.c_str(), &buffer[0], &size ); if( error == PTB_eerrStrBufferTooSmall ) { require_noErr( PTB_ConvertSysToUTF8( source.c_str(), &buffer[0], &size ) ); } return TStringUTF8( buffer.begin() , buffer.begin()+buffer.size()-1 ); } //////////////////////////////////////////////////////////////////////////////// /*! Progress callbacks */ PTB_bool_t progressCB( PTB_uint32_t max /*!< Progress value max */ , PTB_uint32_t current /*!< Current progress value */ , PTB_EPreflightPart part /*!< Current Preflight part in process */ , PTB_StringID idStr /*!< String data */ , void* userData /*!< User data */ ) { CUserdata_t *work = userData ? reinterpret_cast(userData) : 0; if( 0 == work ) return false; PTB_size_t &lastval = work->lastValue; int val( static_cast( static_cast( current) * 100.0 / static_cast( max))); if (lastval != val) { lastval = val; std::stringstream ss; ss << val << "% ["; switch(part) { case PTB_eppPrepare : ss << "Prepare"; break; /*!< Preflight prepare the given input PDF file and resources */ case PTB_eppPreCheck: ss << "PreCheck"; break; /*!< Precheck part of preflight is in process */ case PTB_eppPreCheckDone: ss << "PreCheckDone"; break; /*!< Precheck part of preflight is done without problems. */ case PTB_eppPreCheckHitProblems: ss << "PreCheckHitProblems"; break; /*!< Precheck part of preflight is done and has found some problems. */ case PTB_eppFixup: ss << "Fixup"; break; /*!< Fixup part of preflight is in process */ case PTB_eppFixupDone: ss << "FixupDone"; break; /*!< Fixup part of preflight is done */ case PTB_eppPostCheck: ss << "PostCheck"; break; /*!< Postcheck part of preflight is in process */ case PTB_eppPostCheckDone: ss << "PostCheckDone"; break; /*!< Postcheck part of preflight is done */ case PTB_eppFixupSuccess: ss << "FixupSuccess"; break; /*!< A Fixup was processed successfully */ case PTB_eppFixupFailure: ss << "FixupFailure"; break; /*!< A Fixup was not processed successfully */ case PTB_eppFixupNotRequired: ss << "FixupNotRequired"; break; /*!< No modification was required for an aspect of the pdf file */ case PTB_eppExternalCheck: ss << "ExternalCheck"; break; /*!< Preflight of external referenced pdf files is in process */ }; ss << "] "; ss << getString(idStr); work->log( ss.str() ); // workerConsoleLog (msg); } return true; } //////////////////////////////////////////////////////////////////////////////// // find first profile in engine // userData: PTB_PRCProfID * void FindFirstProfileCB( PTB_PRCEngineID idEng, PTB_PRCProfID idProf, void * userData ) { PTB_PRCProfID * firstProfile = reinterpret_cast< PTB_PRCProfID * >( userData ); if( firstProfile && !PTB_PRCIsValidProfID( *firstProfile ) ) { *firstProfile = idProf; } } void FindFirstProfileCB( PTB_PRCEngineID idEng, PTB_PRCMPrfID idMPrf, void * userData ) { PTB_PRCMPrfID * firstProfile = reinterpret_cast< PTB_PRCMPrfID * >( userData ); if( firstProfile && !PTB_PRCIsValidMPrfID( *firstProfile ) ) { *firstProfile = idMPrf; } } //////////////////////////////////////////////////////////////////////////////// // Log fixups as they occur // userData: NULL void fixupCB( PTB_PRCEngineID idEng /*!< PRC Engine ID */ , PTB_PRCFxupID idFixup /*!< PRC Fixup ID */ , PTB_EFixupState state /*!< Fixup state */ , PTB_StringID idReason /*!< Reason text */ , void* userData /*!< user data */ ) { CUserdata_t *work = reinterpret_cast(userData); if( state != PTB_efsFixupNotRequired ) { work->fixups++; PTB_StringID idFixupName; require_noErr2( PTB_PRCGetFixupData( idEng, idFixup, PTB_PRCEdtName, NULL, &idFixupName ), work, true); std::stringstream ss; // ss << "Fixup \"" << getString( idFixupName, true ) << "\""; ss << "Fixup with state "; switch( state ) { case PTB_efsFixupSuccess : ss << "Success" ; break; case PTB_efsFixupFailure : ss << "Failure" ; break; case PTB_efsFixupNotRequired: ss << "Not Required"; break; } ss << ": \"" << getString( idFixupName, true ) << "\""; const std::string sReason(getString( idReason )); if (sReason.size() > 0) ss << ". Reason: " << getString( idReason ); work->log( ss.str() ); } } //////////////////////////////////////////////////////////////////////////////// // Log hits as they occur // userData: NULL PTB_EHitCBResult hitContinueCB( PTB_PRCEngineID idEng /*!< PRC Engine ID */ , PTB_PRCProfID idProf /*!< PRC Profile ID */ , PTB_PRCRuleID idRule /*!< PRC Rule ID */ , PTB_ResultID idResult /*!< Result ID */ , PTB_HitID idHit /*!< Hit ID */ , PTB_PRCERuleCheckSeverity ruleSev /*!< PRC Rule severity */ , PTB_uint32_t pageNum /*!< Current page number */ , void* userData /*!< user data */ ) { CUserdata_t *work = reinterpret_cast(userData); work->isPDFA = false; work->hits++; PTB_StringID idRuleName; require_noErr2( PTB_PRCGetRuleData(idEng, idRule, PTB_PRCEdtName, NULL, &idRuleName), work, true); std::stringstream ss; ss << "Hit with severity "; switch( ruleSev ) { case PTB_PRCErcsInfo : ss << "Info"; break; case PTB_PRCErcsWarning: ss << "Warning"; break; case PTB_PRCErcsError : ss << "Error"; break; } if(PTB_DOCUMENT_HIT==pageNum) ss << " in document"; else ss << " on page " << pageNum; ss << ": " << getString( idRuleName ); PTB_StringRelease( idRuleName ); work->log( ss.str() ); return PTB_ehcbrContinue; } //////////////////////////////////////////////////////////////////////////////// /*! Save callback // userData: string -> result PDF */ PTB_Path_t* saveCB( PTB_ResultID idResult /*!< Result ID */ , PTB_ESaveAsReason reason /*!< */ , PTB_ESaveAsReasonPDFX reasonPDFX /*!< */ , PTB_EPDFXVersion versionPDFX /*!< */ , PTB_ESaveAsReasonPDFA reasonPDFA /*!< */ , PTB_EPDFAVersion versionPDFA /*!< */ , PTB_StringID currentPath /*!< current path of PDF document */ , void* userData /*!< User data */ ) { if (NULL==userData) return NULL; CUserdata_t *work = reinterpret_cast(userData); const PTB_Path_t *resultPDF = work->outputfile; std::stringstream ss; if( resultPDF != NULL ) { ss << "Saving file to " << resultPDF; work->log( ss.str() ); workerConsoleLog(ss.str()); return const_cast< PTB_Path_t* >( resultPDF ); } else if( PTB_IsValidStringID( currentPath)) { PTB_size_t strBufSize = 0; PTB_EError err = PTB_StringLength( currentPath, &strBufSize); if( err != PTB_eerrNone ) return NULL; std::vector strBuffer(strBufSize); err = PTB_StringGet( currentPath, &strBuffer[0], &strBufSize); if( err != PTB_eerrNone ) return NULL; ss << "Saving file to " << &strBuffer[0]; work->log( ss.str() ); workerConsoleLog(ss.str()); } return NULL; // NULL: use default file stored in 'currentPath' } //////////////////////////////////////////////////////////////////////////////// bool checkVersion() { PTB_uint16_t pdfEngineVersion; PTB_uint16_t apiVersion; PTB_uint16_t apiIteration; PTB_uint16_t buildNumber; PTB_bool_t x64; PTB_bool_t threadSafety; bool ret=true; PTB_EError err = PTB_LibAPIGetVersion2( &pdfEngineVersion , &apiVersion , &apiIteration , &buildNumber , &x64 , &threadSafety); require_noErr( err, false ); std::string arch_info(""); if (x64) arch_info += "x64"; if (threadSafety) { if (arch_info.size() > 0) arch_info += " "; arch_info += "threadSafe"; } std::cout << "callas pdfEngine SDK " << pdfEngineVersion << '.' << apiVersion << '.' << buildNumber; if (arch_info.size() > 0) { std::cout << " (" << arch_info << ")"; } std::cout << std::endl; if (false==threadSafety) { std::cout << "the used PdfEngine does not provide the required ThreadSafety feature" << std::endl; ret=false; } const PTB_uint16_t curPTBVers = dPTBSDK_pdfEngineVersion; const PTB_uint16_t curAPIVersion = dPTBSDK_APIMainVersion; const PTB_uint16_t curAPIIteration = dPTBSDK_APIVersionIteration; if ( curPTBVers != pdfEngineVersion || curAPIVersion != apiVersion //|| curapiIteration < apiIteration //later this should be sufficient. || curAPIIteration != apiIteration //the first prerelease iterations might be incompatible! ) { std::cout << "internal API version mismatch. Expected: " << curPTBVers << "." << curAPIVersion << "." << curAPIIteration << ". Found: " << pdfEngineVersion << "." << apiVersion << "." << apiIteration << std::endl; ret=false; } return ret; } //////////////////////////////////////////////////////////////////////////////// void createReport(CUserdata_t &userdata, const PTB_Path_t* xmlfile) { unsigned int bufSize=0; PTB_ResultID &idResult = userdata.idResult; std::string msg("Creating XML Report "); msg += reinterpret_cast(xmlfile); workerConsoleLog(msg); userdata.log( msg ); userdata.lastValue = 0; // reset progress counter PTB_EError err = PTB_eerrNone; err = PTB_Report( idResult , xmlfile , PTB_eXMLResults_V2 , PTB_eCR , PTB_eUTF8 , 0 , PTB_eAllDetails , NULL , progressCB , &userdata , 0 , PTB_MAX_END_PAGE , NULL ); if (PTB_eerrNone != err) { std::string emsg(getErrorString("PTB_Report", err)); userdata.log( emsg ); workerConsoleLog(emsg); } } PTB_Path_t* sequenceSaveCB( PTB_ESequenceReason reason /*!< */ , PTB_StringID idCurrentPath /*!< current path of PDF document */ , void* userData /*!< User data */ ) { if (userData==0) return NULL; CUserdata_t *work = reinterpret_cast(userData); if( reason == PTB_esrSequenceReport ) { work->log( "Saving report file " + getString( idCurrentPath ) ); } else if( reason == PTB_esrSequenceAction ) { work->log( "Created action result " + getString( idCurrentPath ) ); } else { const PTB_Path_t *resultPDF = work->outputfile; if( resultPDF != NULL ) { work->log( std::string("Saving PDF file ") + reinterpret_cast(resultPDF) ); return const_cast< PTB_Path_t* >( resultPDF ); } else if( PTB_IsValidStringID( idCurrentPath)) { PTB_size_t strBufSize = 0; PTB_EError err = PTB_StringLength( idCurrentPath, &strBufSize); if( err != PTB_eerrNone ) return NULL; std::vector strBuffer(strBufSize); err = PTB_StringGet( idCurrentPath, &strBuffer[0], &strBufSize); if( err != PTB_eerrNone ) return NULL; work->log( std::string("Saving PDF file ") + reinterpret_cast(&strBuffer[0]) ); } } return NULL; // NULL used default file stored in 'idCurrentPath' } void sequenceCB( PTB_PRCEngineID idEng /*!< PRC Engine ID */ , PTB_PRCProfID idProf /*!< PRC Profile ID */ , PTB_PRCRuleID idRule /*!< PRC Rule ID */ , PTB_PRCFxupID idFxup /*!< PRC Fixup ID */ , PTB_PRCActnID idActn /*!< PRC Action ID */ , PTB_ESequenceState state /*!< Sequence state */ , void* userData /*!< User data */ ) { CUserdata_t *work = userData ? reinterpret_cast(userData) : 0; if (work==0) return; std::stringstream oss; switch( state ) { case PTB_essBegin: { oss << "Sequence step begins "; PTB_StringID idStringData=PTB_INVALID_ID; if( idProf != PTB_INVALID_ID ) { oss << "with Profile: \""; require_noErr2( PTB_PRCGetProfileData( idEng, idProf, PTB_PRCEdtName, NULL, &idStringData), work, true); } if( idRule != PTB_INVALID_ID ) { oss << "with Rule: \""; require_noErr2( PTB_PRCGetRuleData( idEng, idRule, PTB_PRCEdtName, NULL, &idStringData), work, true); } if( idFxup != PTB_INVALID_ID ) { oss << "with Fixup: \""; require_noErr2( PTB_PRCGetFixupData( idEng, idFxup, PTB_PRCEdtName, NULL, &idStringData), work, true); } if( idActn != PTB_INVALID_ID ) { oss << "with Action: \""; require_noErr2( PTB_PRCGetActionData( idEng, idActn, PTB_PRCEdtName, NULL, &idStringData), work, true); } oss << getString( idStringData, true ) << "\""; work->log( oss.str() ); work->sindent++; break; } case PTB_essNone : work->log( "Sequence result: None" ); break; case PTB_essInfo : work->log( "Sequence result: Info" ); break; case PTB_essWarning : work->log( "Sequence result: Warning" ); break; case PTB_essError : work->log( "Sequence result: Error" ); break; case PTB_essSuccess : work->log( "Sequence result: Success" ); break; case PTB_essFailure : work->log( "Sequence result: Failure" ); break; case PTB_essEnd: { work->sindent--; work->log( "Sequence step ends" ); break; } } } PTB_EError doKfpProfile( PTB_PRCEngineID idEng , PTB_PRCMPrfID idMPrf , const std::string &inputfile , const PTB_Path_t* saveasfile , const PTB_Path_t* xmlreport , const std::string &logfile , PTB_uint32_t flags) { CUserdata_t userdata(inputfile, saveasfile, logfile); std::string msg; PTB_Path_t filePath[255]; PTB_size_t bufSize = sizeof(filePath); make_ptb_path(inputfile, filePath); PTB_ResultID &idResult = userdata.idResult; PTB_EError err = PTB_PreflightMetaProfile( filePath , idEng /*!< ID of PRC Engine that holds preflight profile */ , idMPrf /*!< ID of PRC profile to be used for preflight check */ , NULL // modifyPRCEnumDynParamCallback , NULL , sequenceCB /*!< CB function to be called for every sequence, might be NULL */ , &userdata /*!< User data submitted to sequence callback function */ , fixupCB /*!< CB function to be called for every fixup, might be NULL */ , &userdata /*!< User data submitted to fixup callback function */ , hitContinueCB /*!< CB function to be called for every hit, might be NULL */ , &userdata /*!< User data submitted to hit callback function */ , progressCB /*!< Progress CB function to be called during processing, might be NULL */ , &userdata /*!< User data submitted to progress callback function */ , sequenceSaveCB /*!< CB function to be called immediately before PDF/X creation, if NULL, no PDF/X PDF/A file gets created, even if requested by preflight profile */ , &userdata /*!< User data submitted to PTB_SaveCB callback function */ , flags /*!< Flags (any combination of PTB_EPreflightFlags values) */ , 0 /*!< First page to be preflighted, this is a zero based index, i.e. first page has value of 0 (zero) */ , PTB_MAX_END_PAGE /*!< Last page to be preflighted; might be INSPK_MAX_END_PAGE for all pages */ , &idResult /*!< On return ID for results from this preflight check, must not be NULL */ , NULL /*!< currently unused for future used */ ); if ((PTB_eerrNone == err) && xmlreport) { createReport(userdata, xmlreport); } userdata.log( getErrorString(err) ); return err; } PTB_EError doKfpProfile( PTB_PRCEngineID idEng , PTB_PRCProfID idProf , const std::string &inputfile , const PTB_Path_t* saveasfile , const PTB_Path_t* xmlreport , const std::string &logfile , PTB_uint32_t flags) { CUserdata_t userdata(inputfile, saveasfile, logfile); std::string msg; PTB_Path_t filePath[255]; PTB_size_t bufSize = sizeof(filePath); make_ptb_path(inputfile, filePath); PTB_ResultID &idResult = userdata.idResult; PTB_EError err = PTB_Preflight5( filePath , idEng /*!< ID of PRC Engine that holds preflight profile */ , idProf /*!< ID of PRC profile to be used for preflight check */ , NULL /*!< CB function to dynamically modify Profile data. Might be NULL */ , NULL /*!< CB user data submitted to CB (for dynamically modifing Profile data.) */ , fixupCB /*!< CB function to be called for every fixup, might be NULL */ , &userdata /*!< User data submitted to hit callback function */ , hitContinueCB /*!< CB function to be called for every hit, might be NULL */ , &userdata /*!< User data submitted to hit callback function */ , progressCB /*!< Progress CB function to be called during processing, might be NULL */ , &userdata /*!< User data submitted to progress callback function */ , saveCB /*!< CB function to be called immediately before PDF/X creation, if NULL, no PDF/X PDF/A file gets created, even if requested by preflight profile */ , &userdata /*!< User data submitted to PTB_SaveCB callback function */ , flags /*!< Flags (any combination of PTB_EPreflightFlags values) */ , 0 /*!< First page to be preflighted, this is a zero based index, i.e. first page has value of 0 (zero) */ , PTB_MAX_END_PAGE /*!< Last page to be preflighted; might be INSPK_MAX_END_PAGE for all pages */ , &idResult /*!< On return ID for results from this preflight check, must not be NULL */ , NULL /*!< currently unused for future used */ ); if ((PTB_eerrNone == err) && xmlreport) { createReport(userdata, xmlreport); } userdata.log( getErrorString(err) ); return err; } //////////////////////////////////////////////////////////////////////////////// int usage() { std::cout << "USAGE:" << std::endl; std::cout << " pdfToolboxSampleThreadSafe [
] [--report] [flags]" << std::endl; std::cout << " flags:" << std::endl; std::cout << " " << PTB_epfNoOptimization << ": Deactivates optimization of the internal structure when saving the PDF" << std::endl; std::cout << " " << PTB_epfUncompressImages << ": Analyzes image pixels for plate count" << std::endl; std::cout << " " << PTB_epfAnalyzeOnly << ": Analyze only; Fixups will not be applied" << std::endl; std::cout << " " << PTB_epfCertify << ": Embed a Preflight Certificate after processing" << std::endl; return EXIT_WITH_FAILURE; } //////////////////////////////////////////////////////////////////////////////// typedef std::vector< std::string > TArgumentVec; const std::string option_value(const std::string &option) { if (option.length() > 2) { return option.substr(2); } else { std::string msg("option "); msg += option; msg += " requires a value"; throw std::invalid_argument(msg); } return ""; } bool next_inputfile(std::string &inputfile) { lock_raii_t lock_(inputqueue_lock); if (inputfiles.empty()) return false; const std::string &tmp=inputfiles.front(); inputfile = tmp; inputfiles.pop_front(); return true; } void work(const std::string &kfpxfile, const std::string &inputfolder, const std::string &outputfolder, bool report_wanted, unsigned int flags) { PTB_EError err = PTB_eerrNone; PTB_PRCEngineID idEng = PTB_INVALID_ID; workerConsoleLog("creating PRCEngine ..."); err = PTB_PRCEngineCreate( &idEng); require_noErr( err ); workerConsoleLog("loading profile ..."); const PTB_Path_t* kfpx = reinterpret_cast< const PTB_Path_t* >(kfpxfile.c_str()); err = PTB_PRCEngineImportPackageFromFile( idEng, kfpx, NULL, NULL); require_noErr( err ); if (PTB_eerrNone != err) { workerConsoleLog("giving up ..."); return; } workerConsoleLog("enumerating profiles ..."); PTB_PRCProfID idProf = PTB_INVALID_ID; PTB_PRCMPrfID idMPrf = PTB_INVALID_ID; err = PTB_PRCEnumMetaProfiles( idEng, FindFirstProfileCB, &idMPrf ); if( err == PTB_eerrNone && PTB_PRCIsValidMPrfID(idMPrf) ) { workerConsoleLog("using MetaProfile"); } else { err = PTB_PRCEnumProfiles( idEng, FindFirstProfileCB, &idProf); } require_noErr( err ); if (PTB_eerrNone != err) { workerConsoleLog("giving up ..."); return; } std::string inputfile; while (next_inputfile(inputfile)) { workerConsoleLog("processing " + inputfile + " ..."); std::string basename; path_basename(inputfile, basename); std::string output_without_ext = path_combine(outputfolder, basename); std::string logfile(output_without_ext + ".log"); PTB_Path_t xmlfile_buf[pathBufSize]; PTB_Path_t savasfile_buf[pathBufSize]; if (idMPrf != PTB_INVALID_ID) { err=doKfpProfile( idEng , idMPrf , inputfile , make_ptb_path(output_without_ext + ".pdf", savasfile_buf) , report_wanted ? make_ptb_path(output_without_ext + ".xml", xmlfile_buf) : NULL , logfile , flags); } else { err=doKfpProfile( idEng , idProf , inputfile , make_ptb_path(output_without_ext + ".pdf", savasfile_buf) , report_wanted ? make_ptb_path(output_without_ext + ".xml", xmlfile_buf) : NULL , logfile , flags); } if (PTB_eerrNone == err) { workerConsoleLog("completed " + inputfile); } else { workerConsoleLog("completed " + inputfile + " (" + getErrorString(err) + ")"); } } if (PTB_INVALID_ID != idEng) PTB_PRCEngineDispose( idEng); } //////////////////////////////////////////////////////////////////////////////// // main //////////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { if( argc < 5 ) { return usage(); } init_sample_locks(); size_t nInputfiles=0; size_t nThreads=omp_get_num_procs(); if (nThreads < 4) nThreads=4; time_t start_time = time(0); try { if (!checkVersion()) { return EXIT_WITH_FAILURE; } PTB_uint32_t flags=0; bool report_wanted=false; TArgumentVec args; for( std::size_t i = 0; i < argc; ++i) { // The second keycode argument (for DeviceLink addon) is optional if( i == 2 ) { std::string tmp( argv[i] ); if( args.at(1) != tmp && tmp.size() != 24 ) { args.push_back( args.at(1) ); } } args.push_back( argv[i] ); std::cout << "argv[" << i << "] = " << args.back() << std::endl; } const std::string kfpxfile(args[3]); if (!path_exists(kfpxfile)) { std::cout << "the given kfpxfile does not exist : " << kfpxfile << std::endl; return EXIT_WITH_FAILURE; } const std::string inputfolder(args[4]); if (!path_exists(inputfolder, true)) { std::cout << "the given inputfolder does not exist : " << inputfolder << std::endl; return EXIT_WITH_FAILURE; } const std::string outputfolder(args[5]); if (!path_exists(outputfolder, true)) { std::cout << "the given outputfolder does not exist : " << outputfolder << std::endl; return EXIT_WITH_FAILURE; } for(int i=6; i> flags; } } // fill input queue scan_inputfolder(inputfolder); nInputfiles=inputfiles.size(); if (0 == nInputfiles) { std::cout << "input folder empty" << std::endl; return EXIT_WITH_FAILURE; } // "embracing" outer SDK init std::cout << "main: initializing SDK ..." << std::endl; require_noErr( PTB_LibInit( args[1].c_str(), args[2].c_str(), 0), true, false ); if (nInputfiles