/*
//
// ADOBE SYSTEMS INCORPORATED
// Copyright (C) 2000-2003 Adobe Systems Incorporated
// All rights reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file
// in accordance with the terms of the Adobe license agreement
// accompanying it. If you have received this file from a source other
// than Adobe, then your use, modification, or distribution of it
// requires the prior written permission of Adobe.
//
*/
#ifdef MAC_ENV
#include "macUtils.h"
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "
CosCalls.h"
#include "
ASCalls.h"
#include "
PDCalls.h"
#include "MyPDFLibUtils.h"
#include "Peddler.h"
#include <stdio.h>
#define URI_K ASAtomFromString("URI")
// Constructor, init's the pdfl
Peddler::Peddler(){
int err = MyPDFLInit(); // initialize the PDFLib
if (err != 0) // check for error after initialization
{
cerr << "Initialization error. See \"AcroErr.h\" for more info.\n" << endl;
cerr << "Error system: " <<
ErrGetSystem(err) << endl;
cerr << "Error Severity: " <<
ErrGetSeverity(err) << endl;
cerr << "Error Code: " <<
ErrGetCode(err) << endl;
return ; // if we cannot init the pdfl, we terminate the application
}
this->theKeyList=
NULL;
}
// ctor initializing the internal files to use
Peddler::Peddler( const string &pdfFile, const string &URIFile){
fPDFFileName = pdfFile;
fURIFileName = URIFile;
int err = MyPDFLInit(); // initialize the PDFLib
if (err != 0) // check for error after initialization
{
cerr << "Initialization error. See \"AcroErr.h\" for more info.\n" << endl;
cerr << "Error system: " <<
ErrGetSystem(err) << endl;
cerr << "Error Severity: " <<
ErrGetSeverity(err) << endl;
cerr << "Error Code: " <<
ErrGetCode(err) << endl;
return ; // if we cannot init the pdfl we terminate the appliation.
}
this->theKeyList=
NULL;
}
// dtor, deletes the keyList if required and terminates the pdfl
Peddler::~Peddler(){
if (this->theKeyList !=
NULL){
delete this->theKeyList;
}
MyPDFLTerm(); // terminate the PDFLib
}
// initially, I am just caching the filename locally as a string, and doing all the work in the
// makeURI method, I will re-factor this in time to move the file level management to this
// method and cache file handles instead...
void
Peddler::SetPDFFile( const string &pdfFile){
fPDFFileName = pdfFile;
}
// initially, I am just caching the filename locally as a string, and doing all the work in the
// makeURI method, I will re-factor this in time to move the file level management to this
// method and cache file handles instead...
void
Peddler::SetURIFile( const string &URIFile){
fURIFileName = URIFile;
}
// doing the actual work. I should abstract this further...
void
Peddler::MakeURIs( const string &outputPDFFile){
volatile
PDDoc pdDoc;
volatile
PDWordFinder wordFinder;
volatile
ASPathName path;
volatile
ASInt32 errCode = 0;
// all our actions with the PDFL occur here, wrap it in an exception block
DURING
#if MAC_ENV
{
//OSErr err;
// Set the working directory where the application was launched from - This must be done after initializing
// the Toolkit
// err = PDFLSetWorkDirToAppDir();
}
#endif
// Open the file that has the key value pairs
this->theKeyList = new keyList();
this->theKeyList->importFile(fURIFileName);
char *file = ( char *)fPDFFileName.data();
if ((pdDoc = MyPDDocOpen(file))==
NULL) {
// If we cannot open the file, we informt he user through cerr, and exit.
// We do this because we understand that we are the outer loop (i.e. there is no exception handler here).
cerr << "Sample application error: Unable to open input PDF file" ;
ASRaise(
ASRegisterErrorString(ErrAlways, "Unable to open input PDF file" ));
}
// cache the document for the wordfinder callback
this->theDoc = pdDoc;
// get the first page before setting up the word finder
this->pdPage =
PDDocAcquirePage (pdDoc, 0);
// Create a word finder that will populate tables of words sorted in PDF order
// and words sorted in x-y order
wordFinder=
PDDocCreateWordFinder(pdDoc,
NULL,
NULL,
NULL, 0, (
WXE_PDF_ORDER |
WXE_XY_SORT),
NULL);
// As the word finder callback is static (for linkage reasons), we need to pass the isntance of the clientData...
PDWordFinderEnumWords(wordFinder,
PDAllPages,ASCallbackCreateProto(
PDWordProc,&(this->TEWordProc)),( void *) this );
#if MAC_PLATFORM
path = GetMacPath(( char *)outputPDFFile.data());
#else
path =
ASFileSysCreatePathName(
NULL,
ASAtomFromString( "Cstring" ), ( char *)outputPDFFile.data(), 0);
#endif
PDDocSave(pdDoc,
PDSaveFull, path,
NULL,
NULL,
NULL);
HANDLER
errCode =
ERRORCODE;
END_HANDLER
if (pdDoc!=
NULL && this->pdPage !=
NULL) {
PDPageRelease(this->pdPage);
}
if (pdDoc!=
NULL && path !=
NULL) {
ASFileSysReleasePath (
NULL, path);
}
if (pdDoc!=
NULL && wordFinder !=
NULL) {
// Destroy the wordfinder
PDWordFinderDestroy(wordFinder);
}
if (pdDoc !=
NULL) {
PDDocClose(pdDoc);
}
if (errCode != 0) {
char buf[256];
ASGetErrorString(
ERRORCODE, buf, sizeof (buf));
fprintf(stderr, "\nError code: %d, Error Message: %s\n" ,
ERRORCODE, buf);
return ;
}
}
// The callback function. The PDFL calls into this function for every word it finds in the document.
// If one of the calls into pdfl throws an exception, I let the outer block catch it, I do not attempt
// to recover from any of the errors (the exceptions that might be thrown either involve a malformed argument
// list, or some protection issue in writing annotations to the file, neither would indicate we should attempt to
// continue with the enumeration).
ACCB1
ASBool ACCB2
Peddler::TEWordProc(
PDWordFinder wObj,
PDWord wInfo,
Int32 pageNum, void * clientData)
{
// get the this pointer and retrieve internal state
Peddler *thisData = (Peddler *)clientData;
keyList * theKL = thisData->theKeyList;
PDDoc docP = thisData->theDoc;
// If we were passed a NULL word, just ignore it
if (wInfo == (
PDWord)
NULL) {
return true ;
}
// we do not handle rotated words...
if (
PDWordIsRotated(wInfo)){
return true ;
}
// if this is our first time through, or the page changes, update our cached copy
if (
PDPageGetNumber(thisData->pdPage) != pageNum) {
thisData->pdPage =
PDDocAcquirePage (docP, pageNum);
}
// space to hold the word
char str[256];
// number of characters in word after filter
ASInt16 retSize;
// get the word
PDWordFilterWord( wInfo, str, 256, &retSize );
// If you'd rather match up punctuation, use the API call below instead
// PDWordGetString(wInfo, str, 256);
// We create a link for each quad, this allows us to hyperlink words that are hyphenated
int numQ =
PDWordGetNumQuads(wInfo);
for ( int i=0; i<numQ; i++ ) {
ASFixedQuad quad;
PDWordGetNthQuad( wInfo, i, &quad );
const string lookupVal = str;
string value = theKL->lookupElement(lookupVal);
if (!value.empty()){
// ths annotation box.
ASFixedRect annotBox;
// define the annotation box
annotBox.
left = quad.
tl.
h;
annotBox.
top = quad.
tl.
v;
annotBox.
right = quad.
br.
h;
annotBox.
bottom = quad.
br.
v;
// create the link annotation
PDAnnot myannot=
PDPageAddNewAnnot(thisData->pdPage, -2,
ASAtomFromString( "Link" ),&annotBox);
// create the link action (it is of type "URI")
PDAction myAct =
PDActionNew(docP, URI_K);
// bind the link annotation to the action
PDLinkAnnotSetAction (myannot, myAct);
// set the color of the annotation to blue
PDColorValue color = new
PDColorValueRec;
color->
space=PDDeviceRGB;
color->
value[0] = 0; // no red
color->
value[1] = 0; // no green
color->
value[2] = 0xffff; // blue
color->
value[3] = 0; // unused
PDAnnotSetColor(myannot,color);
// get the action's associated cos object
CosObj theObj =
PDActionGetCosObj(myAct);
// get the cos document object
CosDoc theDoc =
PDDocGetCosDoc(docP);
// create the cos string that represents the URI
CosObj theURI =
CosNewString (theDoc, false , ( char *)value.c_str(), value.length());
// populate the cos dictionary
CosDictPut(theObj,
ASAtomFromString( "URI" ), theURI);
}
}
return true ;
}