Cuente las páginas en PDF (para usuarios no técnicos, mac)

Tengo una persona que busca contar páginas de quizás 2-3000 PDF. Necesita un recuento total de todos los archivos PDF combinados (probablemente ascenderá a algo así como 20 000 repartidos entre los 3000 archivos PDF); no se necesitan más detalles.

Consideré Adobe Combine y luego obtuve un recuento de páginas, pero solo probando en ~ 500 archivos, ¡es bastante lento!

¡Vale la pena mencionar que solía poder abrir varios archivos PDF simultáneamente en la vista previa y obtener un recuento de páginas! ¡Solía ​​funcionar bastante bien, incluso en 2-300 archivos!

Gracias por tus pensamientos.

¿Quiere saber el recuento de páginas de cada PDF o solo el recuento total de páginas? ¿Los archivos PDF están en una carpeta o en muchas carpetas en un árbol?
recuento total de páginas. no para cada uno. Los archivos están en algunas carpetas, pero puedo hacer que los mueva sin problema.
sería bueno saber si alguna de estas soluciones es más rápida que su método de combinación. El método de combinación es bastante simple y directo. Solo un pensamiento.
El script de @jmh Josh fue mucho, mucho más rápido que fusionar en mi caso de uso (cientos de archivos con cientos de páginas cada uno). Probablemente, una fusión llevaría horas, incluso días, y terminaría con un duplicado de sus archivos (mucho espacio en el disco, en este caso). El guión de Josh tomó minutos (quizás 15 en procesamiento).

Respuestas (2)

Simple.

Cree un Apple Script y expórtelo como una aplicación y luego envíele la aplicación.

Código AppleScript:

set totalPages to 0
set numDocs to 1
set myFiles to choose file with prompt "Select all PDF's" with multiple selections allowed
set nummyFiles to length of myFiles
set progress total steps to nummyFiles
set progress completed steps to 0
set progress description to "Processing PDF's..."
set progress additional description to "Preparing to process."
repeat with i in myFiles
    set progress additional description to "Processing PDF " & numDocs & " of " & nummyFiles
    set progress completed steps to numDocs
    set myfile to POSIX path of i
    set pageCount to (do shell script "/usr/bin/mdls " & quoted form of myfile & " | /usr/bin/awk '/kMDItemNumberOfPages/{print $3}'") as integer
    set totalPages to (totalPages + pageCount)
    set numDocs to (numDocs + 1)
end repeat
display dialog "There are " & totalPages & " pages in this PDF"
  1. Abierto/Applications/Utilities/Script Editor.app
  2. Archivo>Nuevo
  3. Copie y pegue el código anterior
  4. Archivo>Exportar
  5. Formato de archivo: Aplicación
  6. Enviar solicitud exportada
Me preguntaba si myFilespodría romperse con varios cientos de archivos seleccionados. 3,0000 es un montón de archivos. ¿Por qué no hacer que el usuario seleccione una carpeta y luego ejecute el bucle en el script de shell?
Esa es una posibilidad, aunque nunca he visto que eso suceda. ¿Puedes explicar lo que quieres decir? No entiendo que significa tu pregunta.
Voy a probar con 3.000 archivos ahora.
@TonyWilliams ¡Acabo de probar con 3000 archivos y funcionó muy bien! Cada uno tenía 3 páginas por un total de 9.000. Incluso agregué una barra de progreso.
Esto es fantástico. Podrías pulir esto y venderlo en la tienda de aplicaciones. jajaja. Pregunta: ¿Se requiere que se haya completado la indexación de los archivos? Debido a que el recuento de páginas devuelve que soy de ella, parece... bajo.
¡Me alegro de poder ayudar! Desafortunadamente, esta es una limitación de Apple Script. No sé/creo que hay una manera de tener un cuadro de diálogo de carga mientras ingresa todos los archivos en la lista. aunque vere que puedo hacer....
@Gryph Lol eso no es necesario. Pero como es por una buena causa... dona a cualquier organización que creas conveniente. Estoy seguro de que lo apreciarán.

Probé el enfoque de Josh usando mdlsy encontré una cantidad sorprendente de (nulos) para kMDItemNumberOfPages.

Así que cambié de rumbo y usé AppleScriptObjC para contar directamente las páginas en los archivos PDF encontrados.

El script se ejecutará directamente desde Script Editor.app o desde un subprograma de script.

Producirá un informe en TextEdit que se ve así:

--------------------------
PDF files found  :  460
Total Pages      :  27052
Total Errors     :  0
--------------------------

Esta ejecución duró 10 segundos en mi MacBook Pro i7 de mediados de 2010 de 17".

La siguiente línea debe modificarse en el script para reflejar correctamente el directorio de destino en el sistema del usuario:

property searchPath : "~/Downloads"

(Aunque me encantaría que funcione en la ventana frontal del Finder si lo solicita).

Actualmente, el script está configurado para ser recursivo en el directorio de destino.

-------------------------------------------------------------------------------------------
# Auth: Christopher Stone { With many thanks to Shane Stanley and Nigel Garvey }
# dCre: 2018/04/27 01:30
# dMod: 2018/04/27 02:50
# Appl: AppleScriptObjC, TextEdit
# Task: Find all PDF files in a directory tree – count and report all pages.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @TextEdit, @Find, @PDF, @Files, @Directory, @Tree, @Recursive, @Count, @Report, @Pages, @Progress_Bar, @Bar
# Vers: 1.00
-------------------------------------------------------------------------------------------
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "Quartz" -- for PDF features
use scripting additions
-------------------------------------------------------------------------------------------
property searchPath : "~/Downloads"
property searchRecursively : true
-------------------------------------------------------------------------------------------

set pageCountList to {}
set searchPath to ((current application's NSString's stringWithString:searchPath)'s stringByExpandingTildeInPath) as text
set foundItemList to my filteredContents:searchPath withUTI:{"com.adobe.pdf"} |returning|:"path" recursive:searchRecursively

set totalStepNum to length of foundItemList
set progress total steps to totalStepNum
set progress completed steps to 0
set progress description to "Processing PDF's..."
set progress additional description to "Preparing to process."
set numberOfProcessedDocuments to 0

repeat with pdfFilePath in foundItemList
    set numberOfProcessedDocuments to (numberOfProcessedDocuments + 1)
    set progress additional description to "Processing PDF " & numberOfProcessedDocuments & " of " & totalStepNum
    set progress completed steps to numberOfProcessedDocuments
    try
        set anNSURL to (current application's |NSURL|'s fileURLWithPath:(contents of pdfFilePath))
        set theDoc to (current application's PDFDocument's alloc()'s initWithURL:anNSURL)
        set end of pageCountList to theDoc's pageCount() as integer
    on error
        set end of pageCountList to "Error --> " & name of (info for (contents of pdfFilePath))
    end try
end repeat

set errorList to text of pageCountList
set filesFoundCount to length of foundItemList
set pageCountList to integers of pageCountList
set pageCount to its sumList(pageCountList)

set pdfPageReport to "
--------------------------
PDF files found  :  " & filesFoundCount & "
Total Pages      :  " & pageCount & "
Total Errors     :  " & length of errorList & "
--------------------------
"

tell application "TextEdit"
    launch -- prevent the Open dialog from opening.
    activate
    set newDoc to make new document with properties {text:pdfPageReport}
    tell newDoc
        set font to "Menlo"
        set size to "14"
    end tell
end tell

-------------------------------------------------------------------------------------------
--» HANDLERS
-------------------------------------------------------------------------------------------
on filteredContents:folderPath withUTI:wUTI |returning|:returnType recursive:wRecursive
    set theFolderURL to current application's |NSURL|'s fileURLWithPath:folderPath
    set typeIdentifierKey to current application's NSURLTypeIdentifierKey
    set keysToRequest to current application's NSArray's arrayWithObject:(typeIdentifierKey)
    set theFileManager to current application's NSFileManager's defaultManager()

    # Get all items in folder descending into subfolders if asked.
    if wRecursive = true then
        set allURLs to (theFileManager's enumeratorAtURL:theFolderURL includingPropertiesForKeys:keysToRequest options:6 errorHandler:(missing value))'s allObjects()
    else
        set allURLs to theFileManager's contentsOfDirectoryAtURL:theFolderURL includingPropertiesForKeys:keysToRequest options:4 |error|:(missing value)
    end if

    # Build an or predicate to test each URL's UTI against all the specified ones.
    set predArray to current application's NSMutableArray's new()
    repeat with aKind in wUTI
        (predArray's addObject:(current application's NSPredicate's predicateWithFormat_("self UTI-CONFORMS-TO %@", aKind)))
    end repeat
    set thePredicate to current application's NSCompoundPredicate's orPredicateWithSubpredicates:predArray

    # Build a list of those URLs whose UTIs satisfy the predicate …
    script o
        property theURLs : {}
    end script
    # … keeping AS texts listing the UTIs tried so that they don't need to be tested again.

    set conformingUTIs to ""
    set unconformingUTIs to ""

    repeat with oneURL in allURLs
        set thisUTI to end of (oneURL's getResourceValue:(reference) forKey:typeIdentifierKey |error|:(missing value))
        # It's only necessary to test this UTI for conformity if it hasn't come up before.
        set thisUTIAsText to linefeed & thisUTI & linefeed
        if (unconformingUTIs contains thisUTIAsText) then
            # Do nothing.
        else if (conformingUTIs contains thisUTIAsText) then
            # Add this URL to the output list.
            set end of o's theURLs to oneURL
        else if ((thePredicate's evaluateWithObject:thisUTI) as boolean) then -- This works even if thisUTI is missing value.
            # Add this URL to the output list and append the UTI to the conforming-UTI text.
            set end of o's theURLs to oneURL
            set conformingUTIs to conformingUTIs & thisUTIAsText
        else
            # Append this UTI to the unconforming-UTI text.
            set unconformingUTIs to unconformingUTIs & thisUTIAsText
        end if
    end repeat

    # Get an array version of the URL list and use this to derive the final output.
    set theURLs to current application's NSArray's arrayWithArray:(o's theURLs)
    if returnType = "name" then return (theURLs's valueForKey:"lastPathComponent") as list
    if returnType = "path" then return (theURLs's valueForKey:"path") as list
    if returnType = "url" then return theURLs
    return theURLs as list

end filteredContents:withUTI:|returning|:recursive:
-------------------------------------------------------------------------------------------
on sumList(theList)
    set theNSArray to current application's NSArray's arrayWithArray:theList
    set theSum to (theNSArray's valueForKeyPath:"@sum.self") as integer
    return theSum
end sumList
-------------------------------------------------------------------------------------------

Como esta criatura solo se ha probado ligeramente, no doy garantías, pero hasta ahora estoy satisfecho con ella.

-ccs

Interesante: no obtuve ningún valor nulo. Probé varias combinaciones combinadas frente a un conteo de manos frente al enfoque de Josh y todas resultaron iguales. Sin embargo, este método es más rápido, puedo confirmarlo. Sería bueno si uno pudiera dar dos respuestas "correctas".
Solo un seguimiento: este script es mucho más rápido que el script anterior. También es bastante bueno tener la cantidad de archivos PDF contados incluidos y los posibles errores (no he tenido ninguno en múltiples pruebas de cientos de archivos).
Me gustaría trabajar en la combinación de nuestros guiones. Usando su método de conteo, pero el mío de seleccionar el directorio, también agregando la capacidad de seleccionar documentos específicos. Además, creando un método diferente para mostrar resultados.
Lo mejor de ambos mundos, sí, estoy de acuerdo: cada uno tiene diferentes casos de uso, como se indica anteriormente. Puedo usar cualquiera sin problema, pero el tuyo es más fácil para analfabetos. Sin embargo, Christophers es mucho, mucho más rápido. Muy interesante ver las diferencias. Me ha gustado bastante esta pregunta.