He adaptado este c贸digo en C para usarlo desde Harbour:
http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fcpp%2FExtractPDFText%2Fextractpdftext_src.zip&zep=cp%2Fpdf.cpp&obid=7056&obtid=2&ovid=1
Aqui esta mi c贸digo. No funciona con los PDFs que he probado 贸 tal vez a煤n hay alg煤n bug en el c贸digo. Aqui lo comparto por si a alguien le apetece probarlo:
#include "FiveWin.ch"
function Main()
聽 聽local cPDF := MemoRead( "c:\test.pdf" )
聽 聽local nStart := At( "stream", cPDF )
聽 聽local nEnd := At( "endstream", cPDF )
聽 聽local cBuf := Replicate( Chr( 0 ), ( nEnd - nStart ) * 10 )
聽 聽local cText, nResult
聽 聽local hFile
聽 聽while nStart <= Len( cPDF )
聽 聽 聽 nStart = At( "stream", cPDF )
聽 聽 聽 nEnd = At( "endstream", cPDF )
聽 聽 聽 cBuf = Replicate( Chr( 0 ), ( nEnd - nStart ) * 10 )
聽 聽 聽 cText = SubStr( cPDF, nStart + 6, nEnd - nStart )
聽 聽 聽 if Left( cText, 1 ) == Chr( 0x0d ) .and. ;
聽 聽 聽 聽 聽SubStr( cText, 2, 1 ) == Chr( 0x0a )
聽 聽 聽 聽 聽nStart += 2
聽 聽 聽 elseif Left( cText, 1 ) == Chr( 0x0a )
聽 聽 聽 聽 聽nStart++
聽 聽 聽 endif
聽 聽 聽 if SubStr( cText, nEnd - 2, 1 ) == Chr( 0x0d ) .and. ;
聽 聽 聽 聽 聽SubStr( cText, nEnd - 1, 1 ) == Chr( 0x0a )
聽 聽 聽 聽 聽nEnd -= 2
聽 聽 聽 elseif SubStr( cText, nEnd - 1, 1 ) == Chr( 0x0a )
聽 聽 聽 聽 聽nEnd--
聽 聽 聽 endif
聽 聽 聽 HB_ZUNCOMPRESS( SubStr( cPDF, nStart + 6, nEnd - nStart ), @cBuf, @nResult )
聽 聽 聽 cPDF = SubStr( cPDF, nEnd + Len( "endstream" ) + 1 )
聽 聽 聽 ProcessOutput( hFile := fcreate( "c:\test.out", "wb" ), cBuf )
聽 聽 聽 FClose( hFile )
聽 聽 聽
聽 聽 聽 if ! Empty( MemoRead( "c:\test.out" ) )
聽 聽 聽 聽 聽// MsgInfo( MemoRead( "c:\test.out" ), nResult )
聽 聽 聽 endif
聽 聽end
return nil
#pragma BEGINDUMP
#include <hbapi.h>
#include <wtypes.h>
#define oldchar 15
float ExtractNumber(const char* search, int lastcharoffset)
{
聽 聽 聽 聽 float flt=-1.0;
聽 聽 聽 聽 int i = lastcharoffset;
聽 聽 聽 聽 char buffer[oldchar+5];
聽 聽 聽 聽 while (i>0 && search[i]==' ') i--;
聽 聽 聽 聽 while (i>0 && (isdigit(search[i]) || search[i]=='.')) i--;
聽 聽 聽 聽 ZeroMemory(buffer,sizeof(buffer));
聽 聽 聽 聽 strncpy(buffer, search+i+1, lastcharoffset-i);
聽 聽 聽 聽 if (buffer[0] && sscanf(buffer, "%f", &flt))
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 return flt;
聽 聽 聽 聽 }
聽 聽 聽 聽 return -1.0;
}
BOOL seen2(const char* search, char* recent)
{
if ( 聽 聽recent[oldchar-3]==search[0]
聽 聽 聽&& recent[oldchar-2]==search[1]
聽 聽 聽 聽 聽&& (recent[oldchar-1]==' ' || recent[oldchar-1]==0x0d ||
recent[oldchar-1]==0x0a)
聽 聽 聽 聽 聽&& (recent[oldchar-4]==' ' || recent[oldchar-4]==0x0d ||
recent[oldchar-4]==0x0a)
聽 聽 聽 聽 聽)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 return TRUE;
聽 聽 聽 聽 }
聽 聽 聽 聽 return FALSE;
}
#include <hbapifs.h>
static int xputc( unsigned char c, FILE * fo )
{
聽 聽static int iPos = 0;
聽 聽return hb_fsWriteAt( ( HB_FHANDLE ) fo, &c, 1, iPos++ );
}
void ProcessOutput(FILE* file, char* output, size_t len)
{
聽 聽 聽 聽 //Are we currently inside a text object?
聽 聽 聽 聽 BOOL intextobject = FALSE;
聽 聽 聽 聽 //Is the next character literal (e.g. \\ to get a \ character or \( to get ( ):
聽 聽 聽 聽 BOOL nextliteral = FALSE;
聽 聽 聽 聽 //() Bracket nesting level. Text appears inside ()
聽 聽 聽 聽 int rbdepth = 0;
聽 聽 聽 聽 //Keep previous chars to get extract numbers etc.:
聽 聽 聽 聽 char oc[oldchar];
聽 聽 聽 聽 int j=0;
聽 聽 聽 聽 size_t i;
聽 聽 聽 聽 for (j=0; j<oldchar; j++) oc[j]=' ';
聽 聽 聽 聽 for( i=0; i<len; i++)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 unsigned char c = output[i];
聽 聽 聽 聽 聽 聽 聽 聽 xputc( c, file );
聽 聽 聽 聽 聽 聽 聽 聽 if (intextobject)
聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (rbdepth==0 && seen2("TD", oc))
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //Positioning.
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //See if a new line has to start or just a tab:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 float num = ExtractNumber(oc,oldchar-5);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (num>1.0)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc(0x0d, file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc(0x0a, file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (num<1.0)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc('\t', file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (rbdepth==0 && seen2("ET", oc))
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //End of a text object, also go to a new line.
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 intextobject = FALSE;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc(0x0d, file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc(0x0a, file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else if (c=='(' && rbdepth==0 && !nextliteral)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 int num;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //Start outputting text!
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 rbdepth=1;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //See if a space or tab (>1000) is called for by looking
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //at the number in front of (
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 num = ExtractNumber(oc,oldchar-1);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (num>0)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (num>1000.0)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc('\t', file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else if (num>100.0)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc(' ', file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else if (c==')' && rbdepth==1 && !nextliteral)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //Stop outputting text
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 rbdepth=0;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else if (rbdepth==1)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //Just a normal text character:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (c=='\\' && !nextliteral)
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //Only print out next character no matter what. Do not interpret.
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 nextliteral = TRUE;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 nextliteral = FALSE;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if ( ((c>=' ') && (c<='~')) || ((c>=128) && (c<255)) )
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 xputc(c, file);
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 //Store the recent characters for when we have to go back for a number:
聽 聽 聽 聽 聽 聽 聽 聽 for (j=0; j<oldchar-1; j++) oc[j]=oc[j+1];
聽 聽 聽 聽 聽 聽 聽 聽 oc[oldchar-1]=c;
聽 聽 聽 聽 聽 聽 聽 聽 if (!intextobject)
聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 if (seen2("BT", oc))
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 //Start of a text object:
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 intextobject = TRUE;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 }
}
HB_FUNC( PROCESSOUTPUT )
{
聽 聽int iLen = hb_parclen( 2 );
聽 聽// char * buffer = hb_xgrab( iLen );
聽 聽ProcessOutput( ( FILE * ) hb_parnl( 1 ), hb_parc( 2 ), iLen );
聽 聽// hb_storclen( buffer, iLen, 2 );
聽 聽// hb_xfree( buffer );
}
#pragma ENDDUMP