No artigo de hoje, vamos mostrar como juntar arquivos PDF em um só usando AdvPL com GhostScript.
O GhostScript é um projeto conhecido no mundo da programação, que tem uma parte Open Source. Com ele nós conseguimos manipular arquivos PDF.
Um dos recursos interessantes, é o fato de conseguir juntar arquivos. Supondo então, que você tenha a necessidade de juntar 2 ou mais relatórios em AdvPL, nós conseguimos através de uma integração com o GhostScript.
Então antes de mais nada, baixe o GhostScript disponível nesse link – https://www.ghostscript.com/releases/gsdnld.html
Depois de fazer a instalação, baixe o código fonte abaixo, e se atente ao caminho na variável cPastaGS, que é ela que define a pasta onde tem os executáveis do GhostScript.
Dito isso, como é o funcionamento da rotina? Basicamente ela recebe um Array, com todos os arquivos em PDF na estação, e recebe a parametrização de onde que irá gravar o PDF que ficará tudo junto, então ficaria +- assim:
//Arquivos originais que ficarão juntos
aArqOrig := {}
aAdd(aArqOrig, "C:\spool\tst\arquivo1.pdf")
aAdd(aArqOrig, "C:\spool\tst\arquivo2.pdf")
aAdd(aArqOrig, "C:\spool\tst\arquivo3.pdf")
//Define a pasta onde vai gerar o pdf com tudo junto, o nome do pdf e se irá abrir o pdf logo após o processo
cPastaDest := "C:\spool\tst\"
cArquiDest := "tudo_junto.pdf"
lAbrDepois := .F.
//Aciona a função para juntar os PDFs
u_zJuntaPDF(aArqOrig, cPastaDest, cArquiDest, lAbrDepois)
E abaixo segue a função completa do zJuntaPDF que aciona o GhostScript:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} User Function zJuntaPDF
Função para juntar PDFs via Ghost Script
@type Function
@author Atilio
@since 24/08/2023
@version version
@param aArqOrig, Array, Array com todos os arquivos pdfs a serem juntados (mandar com o caminho absoluto)
@param cPastaNovo, Caractere, Caminho da pasta onde vai ser gerado o arquivo novo
@param cArquiNovo, Caractere, Nome do arquivo novo com o conteúdo dos pdfs juntos
@param lAbrirPDF, Lógico, Define se após juntar irá abrir o arquivo novo
@return aRetorno, Array, Posição 1 é se deu tudo certo na geração do arquivo e Posição 2 é o caminho absoluto do arquivo
@obs É necessário instalar o Ghost Script na máquina
Link para download: https://www.ghostscript.com/releases/gsdnld.html
@example
//Arquivos originais que ficarão juntos
aArqOrig := {}
aAdd(aArqOrig, "C:\spool\tst\arquivo1.pdf")
aAdd(aArqOrig, "C:\spool\tst\arquivo2.pdf")
aAdd(aArqOrig, "C:\spool\tst\arquivo3.pdf")
//Define a pasta onde vai gerar o pdf com tudo junto, o nome do pdf e se irá abrir o pdf logo após o processo
cPastaDest := "C:\spool\tst\"
cArquiDest := "tudo_junto.pdf"
lAbrDepois := .F.
//Aciona a função para juntar os PDFs
u_zJuntaPDF(aArqOrig, cPastaDest, cArquiDest, lAbrDepois)
/*/
User Function zJuntaPDF(aArqOrig, cPastaNovo, cArquiNovo, lAbrirPDF)
Local aArea := FWGetArea()
Local lDeuCerto := .F.
Local cComando := ""
Local aRetorno := {}
Local cPastaGS := SuperGetMV("MV_X_GHOST", .F., "C:\Program Files\gs\gs9.55.0\bin\")
Local nAtual := 0
Default aArqOrig := {}
Default cPastaNovo := "C:\spool\"
Default cArquiNovo := "arquivo_junto.pdf"
Default lAbrirPDF := .F.
//Retira os espaços vazios
cPastaNovo := Alltrim(cPastaNovo)
cPastaGS := Alltrim(cPastaGS)
//Adiciona \ caso esteja faltando
cPastaNovo := cPastaNovo + Iif(Right(cPastaNovo, 1) != "\", "\", "")
cPastaGS := cPastaGS + Iif(Right(cPastaGS, 1) != "\", "\", "")
//Verifica se as pastas existem e se tem arquivos
If ! Empty(cPastaGS) .And. ExistDir(cPastaGS) .And. ! Empty(cPastaNovo) .And. ExistDir(cPastaNovo) .And. Len(aArqOrig) > 0
//Monta o comando para converter o PDF
cComando := ' -dBATCH -dNOPAUSE -q '
cComando += ' -sDEVICE=pdfwrite '
cComando += ' -dPDFSETTINGS=/prepress '
cComando += ' -sOutputFile="' + cPastaNovo + cArquiNovo + '" '
//Percorre os arquivos originais
For nAtual := 1 To Len(aArqOrig)
//Se o arquivo existir
If File(aArqOrig[nAtual])
cComando += ' "' + aArqOrig[nAtual] + '"'
EndIf
Next
//Executa o GhostScript
cComando := '"' + cPastaGS + 'gswin64.exe"' + cComando
WaitRun(cComando, 1)
//Se o arquivo existe, deu certo a conversão
If File(cPastaNovo + cArquiNovo)
lDeuCerto := .T.
//Se for para abrir o PDF
If lAbrirPDF
ShellExecute("OPEN", cArquiNovo, "", cPastaNovo, 1)
EndIf
EndIf
EndIf
//Define o retorno
aRetorno := {lDeuCerto, cPastaNovo + cArquiNovo}
FWRestArea(aArea)
Return aRetorno
Bom pessoal, por hoje é só.
Abraços e até a próxima.
funciona no webapp?
Bom dia Rodolfo, tudo joia?
A WaitRun não cheguei a testar, então não vou conseguir afirmar.
Mas a ShellExecute funciona sim, ela funciona desde que esteja instalado o WebAgent na máquina.
Tenha um ótimo e abençoado fim de semana.
Um forte abraço.
vi aqui que funciona sim, mas tive q ajustar a linha q monta o comando pois estava ficando com aspas duplas a mais .
Bom dia Rodolfo, tudo joia?
Ah entendi, depois vou tentar revisar o comando.
Tenha uma ótima e abençoada sexta feira.
Um forte abraço.
retificando aqui …. a função waitrun até funciona sim… mas nao ta executando com o comando do jeito q esta ai no fonte nao. Vou testar com o ShellExecute pra ver
Bom dia Rodolfo, tudo joia?
Opa, obrigado pelo feedback.
Tenta fazer um teste, coloc um breakpoint na linha aue executa o WaitRun / ShellExecute e em seguida, captura a string do comando.
Ai faz um teste direto via prompt de comando no Windows, passa do esse comando pra ver se funciona.
Fico no aguardo.
Tenha uma ótima e abençoada sexta feira.
Um forte abraço.
é, com shellexecute funcionou
Bom dia Rodolfo, tudo joia?
Opa, obrigado pelo feedback.
Tenha uma ótima e abençoada sexta feira.
Um grande abraço.
Boa noite,
Estava rodando na 2310 com sucesso, ao migrar para 2410 o waitrun parou de funcionar. Rodolfo, vc apenas trocou para shellexecute ?
Bom dia Rafael, tudo joia?
Está instalado o WebAgent? Chega a dar alguma mensagem?
Tenha uma ótima e abençoada terça feira.
Um forte abraço.
Opa bom dia,
O WebAgent está instalado sim. Nesta mesma customização tenho outros comandos de sistema operacional como FCreate, FErase, ShellExecute, todos rodando sem problemas.
Apenas o WaitRun é que não executa mais o comando que executava anteriormente.
Por isso que me levou a crer se algo da versão.
Abraços
Bom dia Rafael, tudo joia?
Ah entendi. Tenta fazer um teste então, pega o comando do WaitRun, e da um MemoWrite em um arquivo bat.
E depois via ShellExecute, você abre esse bat.
Segue exemplo:
cPastaTmp := GetTempPath() cArquiTmp := "teste_" + dToS(Date()) + "_" + StrTran(Time(), ":", "-") + ".bat" MemoWrite(cPastaTmp + cArquiTmp, cComando) ShellExecute("OPEN", cPastaTmp + cArquiTmp, "", cPastaTmp, 0 )Tenha uma ótima e abençoada quarta feira.
Um forte abraço.
Boa Tarde Daniel,
Funcionou corretamente, te agradeço muito.
Grande abraço
Bom dia Rafael, tudo joia?
Opa, nós que agradecemos pelo feedback.
Tenha uma ótima e abençoada sexta feira.
Um grande abraço.