› Excel e gli applicativi Microsoft Office › Macro unisci pdf
-
AutoreArticoli
-
Ciao utilizzo questa macro per unire i file .pdf insieme al programma PDF creator
Sub uniscipdf() Dim file1 As String Dim file2 As String file1 = Range("F2").Value ' primo file da unire file2 = Range("F3").Value 'secondo file da unire Dim outPath$ outPath = "C:\test\" & Range("F1").Value Dim oPDF As PdfCreatorObj Set oPDF = New PdfCreatorObj oPDF.AddFileToQueue file1 oPDF.AddFileToQueue file2 Debug.Print "oPDF isinstancerunning: " & oPDF.IsInstanceRunning Dim q As PDFCreator_COM.Queue Set q = New PDFCreator_COM.Queue q.Initialize q.WaitForJobs 2, 10 Debug.Print "q.Count: " & q.Count q.MergeAllJobs Dim job As PDFCreator_COM.PrintJob While q.Count > 0 Set job = q.NextJob job.SetProfileByGuid ("DefaultGuid") job.ConvertTo (outPath) Debug.Print job.IsFinished Debug.Print job.IsSuccessful Debug.Print "q.Count3: " & q.Count Wend EndSub: q.ReleaseCom End SubNella colonna "F" a partire dalla cella F2 ho scritto il percorso dei file da andare ad unire. Quindi nella cella "F2" ho il primo file, nella cella "F3" ho il secondo e così via. Nella cella F1 il nome del file.
Vorrei evitare di dichiarare all'interno dell'istruzione tutte le variabili
Dim file1 As String Dim file2 As String ...e quindi anche
file1 = Range("F2").Value ' primo file da unire file2 = Range("F3").Value 'secondo file da unire ...Questo perché il numero di celle occupate nella colonna "F" può variare e se una cella risulta essere vuota la macro si interrompe perché ovviamente non trova il file.
Avevo pensato di inserire dei case when per gestire un numero di casi prestabiliti e le celle vuote ma mi sembra l'approccio errato. Nel post precedente vecchio frac mi ha spiegato i cicli next, vorrei capire se potrebbe essere questo il caso e come impostarlo.
Allego un file di esempio.
Grazie in anticipo
Allegati:
You must be logged in to view attached files.case when
Bè non stai programmando in SQL mi pare 🙂 L'equivalente in VBA è Select Case ... End Select.
Comunque sì, è come dici:
i cicli next, vorrei capire se potrebbe essere questo il caso e come impostarlo
questo è il caso, secondo me.
Ragionando un attimo, tu devi eseguire l'istruzione
oPDF.AddFileToQueueun certo numero di volte, indeterminato a priori, ma finito e delimitato da un certo range di valori. Certo che se tu ammetti celle vuote (da bypassare) allora il punto finale deve essere un'altra cella (ad esempio sai che il range ammesso va da F2 a F50) oppure finchè non inserisci una parola convenzionale per indicare fine ciclo (esempio, in una cella scrivi "STOP").L'algoritmo è:
- inizia un ciclo nel range che parte da F2 in avanti (fino alla cella finale oppure finchè non trovi una parola chiave in una cella)
- ad ogni passata del ciclo la variabile di controllo assume il valore di ogni cella del range
- quindi imposti l'istruzione che accoda all'oggetto oPDF la variabile di controllo che rappresenta la cella corrente
- concludi il ciclo passando al valore successivo
Ciao. Dunque ho scopiazzato dalla tua macro precedente..spero di aver capito bene. Ho dichiarato la variabile c e dato che le l'intervallo delle celle sono contigue ho definito il range di conseguenza.
Sub uniscipdf() Dim c As Range Dim outPath$ outPath = "C:\test\" & Range("F1").Value Dim oPDF As PdfCreatorObj Set oPDF = New PdfCreatorObj For Each c In Worksheets("Foglio1").Range("F2", ActiveSheet.Range("F1").End(xlDown)) 'oPDF.AddFileToQueue file1 Debug.Print "oPDF isinstancerunning: " & oPDF.IsInstanceRunning Dim q As PDFCreator_COM.Queue Set q = New PDFCreator_COM.Queue q.Initialize q.WaitForJobs 2, 10 Debug.Print "q.Count: " & q.Count q.MergeAllJobs Dim job As PDFCreator_COM.PrintJob While q.Count > 0 Set job = q.NextJob job.SetProfileByGuid ("DefaultGuid") job.ConvertTo (outPath) Debug.Print job.IsFinished Debug.Print job.IsSuccessful Debug.Print "q.Count3: " & q.Count Wend EndSub: q.ReleaseCom End Subè giusto fino a qui ? come faccio ad impostare l'istruzione successiva?
Dunque direi che ci siamo come logica ma attenzione che:
For Each c In Worksheets("Foglio1").Range("F2", ActiveSheet.Range("F1").End(xlDown))
questo imposta un ciclo nel range del Foglio1 che va da F2 (del foglio attivo) all'ultima cella occupata del foglio attivo a partire da F1.
Alcune imprecisioni:
- se sei su un foglio diverso, i riferimenti al Foglio1 (o dove si trovano i dati) devono essere qualificati affinché funzionino correttamente, e ciò va fatto ogni qual volta ti riferisci a un range;
- il calcolo dell'ultima cella occupata di un range, utilizzando il metodo con End, è leggermente diverso da come l'hai impostato, eccome dovrebbe essere:
Range("F2", Cells(Rows.Count, "F").End(xlUp))così imposti un riferimento al range F2:Fxx (dove xx è l'ultima cella piena in colonna F);
- per rispondere alla tua domanda, "come faccio ad impostare l'istruzione successiva?", devi pensare alla sintassi di For;
- dentro il ciclo, imposti l'istruzione che aggiunge il valore della cella corrente alla coda di oPDF (hai commentato la riga nel tuo codice, decommentala perchè è giusta, solo che invece che file1 devi scrivere ... ?
Come suggerimento finale ti consiglio ti dichiarare tutte le variabili dopo la firma della procedura; cioè: dopo la dichiarazione tipo Sub xyz() metti subito sotto i diversi Dim che dichiarano e tipizzano le variabili in uso nel programma.
solo che invece che file1 devi scrivere
aggiorno
oPDF.AddFileToQueue (c)così funziona. Spero sia giusto.
Però la prima volta che ho esguito la macro è crashato excel e la seconda lo ha esportato ma mi ha dato comunque errore. C'è qualcosa che si potrebbe ridurre in questa macro? Non mi è mai piaciuta molto ad esser sincero
aggiorno

mi ha dato comunque errore
Ricordi quale e su che riga?
Può darsi che ci sia qualcosa che confligge in memoria. Non ho installato PDF Creator qui, dovrei provare i una macchina virtuale, ma adesso mi manca il tempo.
l'errore varia è veramente strano. A volte mi da errore presso
q.Initializeperchè il processo è già in in corso. E mi sono accorto che non unisce sempre tutti i PDF . A volte solo i primi due oppure 7, o 8. Probabilmente è proprio un problema di memoria come dici tu perché se tipo di 20 pdf ne unisce solo 4 se apro il programma PDF creator mi chiede subito se voglio unire i 16 pdf restanti. Ho visto sul forum del programma che il problema è ricorrente.
Ad ogni modo allego il codice completo:
Sub uniscipdf() Dim c As Range Dim oPDF As PdfCreatorObj Dim q As PDFCreator_COM.Queue Dim outPath$ outPath = "C:\test\" & Range("F1").Value Set oPDF = New PdfCreatorObj For Each c In Worksheets("Foglio1").Range("F2", Cells(Rows.Count, "F").End(xlUp)) oPDF.AddFileToQueue (c) Debug.Print "oPDF isinstancerunning: " & oPDF.IsInstanceRunning Set q = New PDFCreator_COM.Queue q.Initialize q.WaitForJobs 2, 10 Debug.Print "q.Count: " & q.Count q.MergeAllJobs Dim job As PDFCreator_COM.PrintJob While q.Count > 0 Set job = q.NextJob job.SetProfileByGuid ("DefaultGuid") job.ConvertTo (outPath) Debug.Print job.IsFinished Debug.Print job.IsSuccessful Debug.Print "q.Count3: " & q.Count Wend EndSub: q.ReleaseCom End SubComunque grazie mille vecchio frac per avermi seguito e soprattutto spiegato. Sto imparando molto grazie ancora
Non sono riuscito a ricreare la situazione ma se il tuo problema di fondo è rimasto lo stesso (combinare un pdf da più file pdf) allora ti suggerisco il mio metodo, che uso con successo da anni, funziona egregiamente e non devi neppure installare componenti strani nè creare oggetti in memoria.
Io utilizzo (per questo ma anche per altre operazioni sui pdf) uno strumento che si chiama pdftk, puoi cercarlo con Google, è un programmino da richiamare in una Shell e fa tutta l'operazione (e anche di più: estrae, combina, ruota, aggiunge watermark ecc.).
Se sei interessato ti approfondisco l'uso di questo strumento. Altrimenti vediamo di risolvere con PDFCreator ma dubito di riuscire ad essere più efficace di altri che hai già consultato.
ho provato a reinstallare il programma (avevo la 3.2.0 ho aggiornato alla 3.2.2) e sembra funzionare. Ma comunque non mi fido!
Se hai tempo mi interesserebbe molto tanto devo solo unire i file niente di più
Ti dirò, PDFCreator è un bel programma davvero. E non c'è ragione a non fidarsi, l'ho utilizzato anch'io per qualche tempo (smazzandomi pure io con il suo modello COM), poi ho scoperto pdftk che fa egregiamente quello che mi serviva... ora non lo uso più, anche perchè trovo più rapido creare pdf direttamente da Word o Excel, e quando poi devo fare operazioni più complesse (che ti ho già illustrato) vado di batch con pdftk e vivo felice... quindi domani in ufficio raccolgo materiale e ti passo tutte le info (intanto fatti un giro su Google cercandolo, è free e pure ben documentato con gli esempi più utili).
Qui è come faccio io, ridotto all'osso:
Option Explicit Sub combina() Const pdftk = """C:\UTILS & TOOLS\pdf-tk\pdftk.exe""" Const SW_HIDE = 0 Dim riga_di_comando As String Dim list_of_files As String Dim output_file As String Dim r As Range ' sintassi: pdftk in1.pdf in2.pdf cat output out1.pdf riga_di_comando = "" list_of_files = "" For Each r In Range("A1:A3") riga_di_comando = riga_di_comando & Chr(34) & r & Chr(34) & " " Next riga_di_comando = riga_di_comando & "cat output " output_file = "C:\PROVA\merged_file.pdf" riga_di_comando = riga_di_comando & Chr(34) & output_file & Chr(34) ShellEX pdftk & " " & riga_di_comando, SW_HIDE Or 1, True MsgBox "Fatto" End Sub 'esegue una shell in modo SINCRONO, quindi attende il termine dell'esecuzione per proseguire Public Function ShellEX(ByVal Percorso As String, ByVal windowstyle As Integer, ByVal Wait As Boolean) As Boolean Dim wshell As Object On Error GoTo Err_Shell ShellEX = False Set wshell = CreateObject("WScript.shell") wshell.Run Percorso, windowstyle, Wait Set wshell = Nothing ShellEX = True Exit_Here: Exit Function Err_Shell: Resume Exit_Here End FunctionQuando scarichi l'applicazione (che è a riga di comando quindi non si installa niente) ti trovi essenzialmente l'eseguibile e la sua dll (oltre al file di help che ti consiglio di conservare), metti tutto in una directory facilmente accessibile al tuo programma e costruisci la stringa di comando che poi gli darai in pasto con la piccola routine di ShellExecute che pure ti allego.
Vedi se riesci a capire come funziona nel dettaglio, altrimenti poi lo rivediamo insieme.
Ciao, ho installato il programma dopo aver scaricato l'installer...ho fatto una prova volante così:
`Sub combina() Const pdftk = """C:\Program Files (x86)\PDFtk\pdftk.exe""" Const SW_HIDE = 0 Dim riga_di_comando As String Dim list_of_files As String Dim output_file As String Dim r As Range ' sintassi: pdftk in1.pdf in2.pdf cat output out1.pdf riga_di_comando = "" list_of_files = "" For Each r In Range("F2:F3") riga_di_comando = riga_di_comando & Chr(34) & r & Chr(34) & " " Next riga_di_comando = riga_di_comando & "cat output " output_file = "C:\temp\merged_file.pdf" riga_di_comando = riga_di_comando & Chr(34) & output_file & Chr(34) ShellEX pdftk & " " & riga_di_comando, SW_HIDE Or 1, True MsgBox "Fatto" End Sub`Esegue la macro senza errori ma non mi da nessun file in output. Nelle celle F2 e F3 ho scritto il percorso dei singoli file pdf che voglio unire
Nelle celle F2 e F3 ho scritto il percorso dei singoli file
Ok, hai scritto il percorso e il nome completo dei file, compresa l'estensione pdf ?
La prova migliore che puoi fare per vedere che errori ti dà è quella di eseguire il comando pdftk in una shell di DOS. Dal terminale raggiungi la cartella dove hai pdftk.exe e costruisci il comando completo:
pdftk "file1.pdf" "file2.pdf" "file3.pdf" cat output "c:\temp\merged.pdf"Le virgolette sono necessarie se ci sono degli spazi nei nomi di file (percorso + nomefile).
Dopo l'esecuzione del comando nella cartella C:\temp deve esserci il file unificato.
Altrimenti otterrai una serie di avvisi di errore che puoi riportare qui così li esaminiamo.
dunque da riga di comando funziona.
Ho riprovato a mettere anche le virgolette nel nome della cella ("C:\temp\prova1.pdf") ma non funziona lo stesso
Bene se funziona da shell è positivo.
Metti un breakpoint su ShellEx, esegui e quando si ferma, in Immediata chiedi il valore del comando in esecuzione con
? pdftk & " " & riga_di_comandoQuindi incolla qui il risultato, e vediamo che succede.
fatto
"C:\Program Files (x86)\PDFtk\pdftk.exe" ""C:\temp\prova2.pdf"" ""C:\temp\prova1.pdf"" cat output "C:\temp\merged.pdf"
Ci sono troppe virgolette nei nomi di file, strano.
Modifica:
riga_di_comando = riga_di_comando & Chr(34) & r & Chr(34) & " "in:
riga_di_comando = riga_di_comando & r & " "e riprova. Però non dovrebbe essere così. Le mie prove erano buone col codice che ho mostrato.
Dici che da riga di comando funziona. Come l'hai scritta l'istruzione? senza le doppie virgolette vero?
ho riprovato e non funziona.
L'istruzione da riga di comando l'ho scritta così
pdftk C:\temp\prova2.pdf C:\temp\prova1.pdf cat output c:\temp\merged.pdf
senza virgolette. Se metto le virgolette non esegue l'istruzione. Anche nelle celle il percorso è scritto senza virgolette
Le virgolette sono necessarie quando ci sono degli spazi nel percorso o nel nome del file.
Questo da riga di comando dovrebbe funzionare ugualmente:
pdftk "C:\temp\prova2.pdf" "C:\temp\prova1.pdf" cat output "c:\temp\merged.pdf"ed è esattamente questo il risultato che dobbiamo affidare a ShellEx (certamente, la costante pdftk utilizza le triple virgolette perchè così serve a ShellEx).
@thunder voglio risolvere questa cosa che anche a me è costata settimane di lavoro ma alla fine ho ottenuto risultati splendidi 🙂 Quindi non rinunciare
Questo da riga di comando dovrebbe funzionare ugualmente:
hai ragione. Ho riprovato con la tua stringa e funziona. Ti allego il mio file se hai tempo di darci un occhio. probabilmente ho sbagliato anche lì ma non me ne accorgo.
Allegati:
You must be logged in to view attached files.Solo una domanda banale... ma il percorso *esatto* di pdftk sul tuo pc qual è?
Perchè ho scaricato l'installer e l'ho installato su macchina virtuale, ha creato tutto il suo percorso ed è finito qui:
C:\Program Files\PDFtk\bin\pdftk.exeIl dubbio mi è sorto perchè nel tuo file il percorso della "const pdftk" è leggermente diverso.
Ho appena terminato la prova.
Il programma funziona benissimo e fonde i pdf specificati. Secondo me hai solo sbagliato a indicare il percorso di pdftk.exe :).
Sub combina() Const pdftk = """C:\Program Files (x86)\PDFtk\bin\pdftk.exe""" '<--- percorso dell'eseguibile! Const SW_HIDE = 0 Dim riga_di_comando As String Dim list_of_files As String Dim output_file As String Dim r As Range ' sintassi: pdftk in1.pdf in2.pdf cat output out1.pdf riga_di_comando = "" list_of_files = "" For Each r In Range("F2:F3") riga_di_comando = riga_di_comando & Chr(34) & r & Chr(34) & " " Next riga_di_comando = riga_di_comando & "cat output " output_file = "C:\temp\merged_file.pdf" riga_di_comando = riga_di_comando & Chr(34) & output_file & Chr(34) ShellEX pdftk & " " & riga_di_comando, SW_HIDE, True 'esegue il comando senza la finestra DOS MsgBox "Fatto" End Sub -
AutoreArticoli
