我有一个根目录C:\ROOT
,该目录包含许多子文件夹,这些子文件夹的名称已经按正确的顺序排列,例如:
C:\Root\Folder0001
C:\R00t\Folder0002
C:\R00t\Folder0003
...
C:\ROOT\Folder000n
子文件夹的总数不固定,但如果需要,可以使用。无论如何,C:\Root_Folder
必须处理其中的所有目录。
每个子文件夹仅包含 JPG 文件,没有其他内容,并且每个子文件夹中的文件数量并不相同。JPG 文件已按正确的顺序命名,例如:
C:\Root\Folder0001\File0001.jpg
C:\Root\Folder0001\File0002.jpg
C:\Root\Folder0001\File0003.jpg
C:\Root\Folder0002\File0001.jpg
C:\Root\Folder0002\File0002.jpg
C:\Root\Folder0002\File0003.jpg
C:\Root\Folder0002\File0004.jpg
C:\Root\Folder0002\File0005.jpg
C:\Root\Folder0003\File0001.jpg
C:\Root\Folder0003\File0002.jpg
C:\Root\Folder0004\File0001.jpg
C:\Root\Folder0004\File0002.jpg
C:\Root\Folder0004\File0003.jpg
C:\Root\Folder0004\File0004.jpg
C:\Root\Folder0005\File0001.jpg
C:\Root\Folder0005\File0002.jpg
C:\Root\Folder0005\File0003.jpg
C:\Root\Folder0005\File0004.jpg
我需要一个批处理文件,根据输入的根目录(C:\ROOT
)将单个子文件夹中的所有 JPG 文件合并到一个 PDF 文件中,并将该 PDF 文件放在子文件夹本身中。
必须对 ROOT 下的所有子文件夹执行此操作,为每个子文件夹创建一个 PDF 文件。
如果合并后删除 JPG 文件,并且 PDF 文件具有与包含文件夹相同的名称,那就完美了,即:
C:\Root\Folder0001\Folder0001.pdf
C:\Root\Folder0002\Folder0002.pdf
C:\Root\Folder0003\Folder0003.pdf
C:\Root\Folder0004\Folder0004.pdf
C:\Root\Folder0005\Folder0005.pdf
答案1
传统的使用 Windows 提供的工具进行批量处理无法生成 PDF,需要安装单独的工具。
将图像转换为 PDF Ghostscript就足够了。如何使用它的示例可以在堆栈溢出或者这里。
正如示例所示,使用 Ghostscript 并不好玩。我建议添加工具包图像魔术师(下载 Windows 版本)。对于 PDF 创建,它依赖于 Ghostscript 并提供了一个相当直接的命令行:
convert "*.jpg" -quality 80 -adjoin "result.pdf"
这会将*.jpg
当前目录中按字母顺序排列的所有 JPEG 文件 ( ) 转换为文件result.pdf
。执行此操作时,它会以 80% 的压缩质量压缩 JPEG 文件 ( -quality 80
),并将每个 JPEG 文件作为新页面添加到文档 ( -adjoin
)。
将其包装到批处理中
- 递归当前位置的所有子目录
- 创建当前子目录中所有 JPEG 的 PDF
- 使用与当前子目录相同的名称命名 PDF
- 完成后删除 JPEG(此处禁用
REM
)
文件:create-all-pdfs.bat
@echo off
for /f "usebackq tokens=*" %%i in (`dir /b /s /a:d`) do @(
echo %%i
Magick convert "%%i\*.jpg" -quality 80 -adjoin "%%i\%%~nxi.pdf" 2>nul
REM if NOT ERRORLEVEL 1 del "%%i\*.jpg"
)
为了安全起见,PDF 创建后删除文件的操作已被注释掉。
=> 取消注释风险自负!
=> 但首先请阅读注释。
更好的是,在您创建并验证 PDF 后,您可以从同一个文件夹中执行此批处理以递归删除所有 JPEG:
文件: delete-all-jpegs.bat
@echo off
for /f "usebackq tokens=*" %%i in (`dir /b /s /a:d`) do @(
echo %%i
del "%%i\*.jpg"
)
注释 1:正确的图像尺寸
PDF 处理文档页面。此类文档页面具有实际测量值(厘米/英寸)。因此,插入 PDF 页面的图片的密度应在元数据中定义(即 300ppi)。
如果不是这种情况或值不合适,则图像可能会显示得太小或太大。
- 要么在 JPEG 中定义正确的值
- 或者您可以通过
Magick
命令参数定义用于处理图像的值:
-density 300
定义图片的分辨率为 300 ppi(每英寸像素数)
Magick convert "%%i\*.jpg" -density 300 -quality 80 -adjoin "%%i\%%~nxi.pdf"
如果图片在 PDF 中显示得太小,请降低密度值。
注释2:JPEG 将被重新编码
您需要知道 Imagemagickconvert
始终会解释图像。因此,JPEG 在处理为 PDF 时将被重新编码。由于 JPEG 使用破坏性压缩,因此这很重要。
为了获得最佳效果,您的 JPEG 应该不是以压缩格式保存(质量:100%)。压缩应由 Imagemagick 的 完成convert
。
注释 3:批处理/命令行中的变量
请注意,这些代码行是为了在批处理文件中执行而编写的。命令变量必须有双重%
=> %%i
。
在命令行中您只需使用一个%
=> %i
。
注释4:如何显示当前的JPEG文件
我如何回显当前正在处理的文件(不仅仅是文件夹 %%i)?
首先要意识到的是,批处理本身目前不知道任何文件名,它只知道它传递给的目录名Magick convert
。
要显示当前处理的文件名,有两种方法:
1. cmd shell 例程的输出
要通过 cmd shell 执行此操作,必须重写批处理以评估每个 JPEG 文件名并将其Magick
逐一传递给。
这样做的问题在于性能,因为你想在一个 PDF 中填充一个目录的所有 JPEG。所以PDF 会为每个 JPEG 进行重写!而不是只创建一次。
Magick ...
用这段代码替换脚本中的这一行就可以了,但是已贬值:
for %%f in ("%%i\*.jpg") do @(
Magick convert "%%i\%%~nxi.pdf" "%%f" -quality 80 -adjoin "%%i\%%~nxi.pdf"
)
更好的:
2. 要求Magick
显示当前文件名
问题在于,Magick 不是一款用于制作漂亮输出的工具,而是一款用于进行智能图像处理的工具。——至少我没有找到简单的选项仅显示当前处理的图像文件。
该选项-verbose
包含此信息,但远不止于此。
所以我过滤了输出以-verbose
达到目的。这是最终的扩展脚本:
@echo off
for /f "usebackq tokens=*" %%i in (`dir /b /s /a:d`) do @(
echo %%i
Magick convert "%%i\*.jpg" -quality 80 -adjoin -verbose "%%i\%%~nxi.pdf" 2>nul | (
for /f "tokens=1,2 delims=>=[" %%f in (
'find /v "1x1"'
) do @(
echo %%g | find /v /i ".pdf" >nul && echo %%f
echo %%g | find /i ".pdf"
)
)
REM if NOT ERRORLEVEL 1 del "%%i\*.jpg"
)
请注意,该选项-verbose
必须写入源文件和目标文件之间!
本来可以有一个稍微容易一些的变体来过滤-verbose
,但根据目前的变体,文件确实处理时显示。最后,PDF 文件的组装也需要花费相应的时间,因此也会显示出来。
如果您不想看到最终的 PDF,请删除该行echo %%g | find /i ".pdf"
。
答案2
@echo off
cd /d "D:\Full\Path\To\Ur\Given\In\Input\The\Root\Dir"
set "_jpeg2pdf="D:\The\Full\Path\To\Bin\jpeg2pdf.exe""
set "_jpeg2pdf=%_jpeg2pdf% -p A4 -n auto -z fit -c none .\*.jpg -o"
for /r /d %%i in (*)do chDir /d "%%~dpnxi" && =;(
@%_jpeg2pdf% ".\%%~nxi.pdf" | find /i ".pdf"
if exist ".\\%%~nxi.pdf" 2>nul del ".\*.jpg"
);=
"%__AppDir__%tree.com" /f /a "%~dp0" | "%__AppDir__%more.com"
jpeg2pdf.exe
通过 JPEG 扫描和照片创建 PDF:@dmitry-markin、@haohu
如何使用
1.document.pdf
从所有 JPEG 文件创建 PDF在当前目录中:
jpeg2pdf *.jpg -o document.pdf
2.创建 PDF scans.pdf
:页面大小由最大图像大小决定,页面方向强制为portrait
,保留图像的原始 dpi(不缩放),在图像边界处裁剪每页的高度(对于具有白色背景和正确 dpi 的扫描可产生良好的效果)
jpeg2pdf -o scans.pdf -p auto -n portrait -z none -r height *.jpg
3.创建 PDF“from_photos.pdf”:A5 纸张大小、横向、适合图像宽度(fw
--适合宽度)、裁剪每页高度(适用于正确裁剪横向 A5 页面照片,dpi 未知/错误,宽度大致正确)
jpeg2pdf -o from_photos.pdf -p A5 -n landscape -z fw -r height *.jpg
4.可以使用开关指定生成的 PDF 文档的标题、作者、主题、关键字和创建者-t, -a, -s, -k, -c
:
jpeg2pdf -o doc.pdf -t "The Title of PDF" -a Andrew -c jpeg2pdf *.jpg
项目主页
http://sourceforge.net/projects/jpeg2pdf/
> jpeg2pdf.exe -h
Usage: jpeg2pdf.exe [options] filemask-1 ... [filemask-N]
-o output output PDF file name. required.
[-p papersize] A0-A10,Letter,Legal,Junior,Ledger,Tabloid,auto default:A4
[-n orientation] auto,portrait,landscape default:auto
[-m marginsize] margins size in inches (specify 'mm' for millimeters) default:0
[-z scale] fit,fw,fh,reduce,rw,rh,none default:fit
[-r crop] none,height,width,both default:none crop/expand page to image size
[-t title] default: none
[-a author] default: current user name
[-k keywords] default: input files list
[-s subject] default: 'Generated from JPEG images'
[-c creator] default: 'jpeg2pdf'
[-h] display this help
filemask-... input JPEG file name. requires at least one. wildcards '*' and '?' allowed.
我倾向于优先使用简化的二进制文件,并且基于此我总是使用 jpeg2pdf 将 jpg 转换为 pdf,因此我有点怀疑它的好坏,所以我只会说我更喜欢它,因为它很简单并且无论何时使用它它都能为我提供很好的服务。
请注意,软件不能很好地处理文件路径,它更喜欢在本地处理它们(如何使用物品1.),因此需要进入文件所在的文件夹才能进行转换。
jpeg2pdf.exe "D:\Full\Path\To\Ur\Given\In\Input\The\Root\Dir\*.jpg" "%%~nxi.pdf"
chDir /d "%%~dpnxi"
jpeg2pdf.exe *.jpg ".\%%~nxi.pdf"
因此,下载jpeg2pdf
并将其放在某个文件夹中并替换相关路径。
set "_jpeg2pdf="D:\The\Full\Path\To\Bin\jpeg2pdf.exe""
您可以使用for /d /r
循环,它将递归遍历所有文件夹,并在循环中的每个文件夹中使用cd /d
命令后跟jpeg2pdf
转换您的jpg
在当前文件夹中,完成后,如果 pdf 是在那里生成的,则删除文件夹中的所有 *.jpg。
FOR /R - Loop through files (recursively) FOR /D - Loop through several folders/directories
The option /D /R is undocumented, but can be a useful combination, while it will recurse through all subfolders the wildcard will only match against Folder/Directory names (not filenames) Note: Source linked to ss64.com
其他资源:
答案3
OP 暗示的挑战是仅使用 Windows 原生 Opp。系统从文件夹中合并的 JPG 生成 PDF。实际上,使用 Windows TAR 合并为 zip 非常简单,但如果没有 GUI 应用程序,将其转换为 PDF 则比较困难。
有很多关于“不可能”的评论,我同意这确实很难,但是鉴于某些 Windows 功能,这并非不可能。
因此,无效的意图将使用可以合并 pdf 等的 PowerShell PSWritePDF 模块,但会导入 Apryse iText(作为下载),请参阅后面的评论。
可以使用 JScript 编写一个文本包装器来包装基线 JPEG,因为它们可以自然地作为页面嵌入到 PDF 中。参见https://stackoverflow.com/a/75710613/10802527为原则。
在这一点上,我会说我可以编写一个 Console.CMD 脚本来轻松完成该任务(JPEG/MP4)但生命短暂,因此有一个针对单个文件的概念证明https://github.com/GitHubRulesOK/MyNotes/blob/master/jpgTOpdf.zip
此代码片段是一个文本文件,用于生成一个小型 PDF 作为 JScript(或 WSH 或 VBS)的 POC,它更容易像双击.js 一样快速运行
注意:记事本不会破坏此 ANSI 二进制文件,但 Web 复制和粘贴会破坏此二进制文件,因此这里有一个下载链接https://github.com/GitHubRulesOK/MyNotes/blob/master/JScriptSamples/HWR%26Wstream.js
var ByteStream = new ActiveXObject("ADODB.Stream");
ByteStream.Type = 2; // Writer
ByteStream.Charset = "Windows-1252"; //Best for PDF writer
var BS = ByteStream; // Abreviate for ease of edit
BS.Open();
BS.Position = 0;
BS.WriteText("%PDF-1.0\n");
BS.WriteText("%Åѧ¡\n");
BS.WriteText("1 0 obj <</Type/Catalog/Pages 2 0 R>> endobj\n");
BS.WriteText("2 0 obj <</Type/Pages/Count 1/Kids[3 0 R]>> endobj\n");
BS.WriteText("3 0 obj <</Type/Page/MediaBox[0 0 144 144]/Rotate 0/Resources<</XObject<</Img0 4 0 R>>>>/Contents 5 0 R/Parent 2 0 R>> endobj\n");
BS.WriteText("4 0 obj <</Type/XObject/Subtype/Image/Height 25/Width 24/BitsPerComponent 1/Length 75/ColorSpace[/Indexed/DeviceRGB 1<FF0000FFFFFF>]>> stream\n");
BS.WriteText('ÿÿÿÿÿÿÀmß[}ÑoEÑ[EÑqEßE}ÀUÿñÿÁ«Á¬ÛZcýÖÇÈ"}ÿÕïÀMsß`§Ñ]9ÑNÑE·ßLÇÀA[ÿÿÿÿÿÿ');
BS.WriteText("\nendstream\nendobj\n");
var Pos1 = "000000000"+BS.Position
BS.WriteText("5 0 obj <</Length 101>> stream\n");
BS.WriteText("q\n1 0 0 -1 18 54 cm\n35 0 0 -36 0 36 cm\n/Img0 Do\nQ\nq\n1 0 0 -1 71 144 cm\n70 0 0 -72 0 72 cm\n/Img0 Do\nQ\n");
BS.WriteText("\nendstream\nendobj\n\n");
var Pos2 = BS.Position
BS.WriteText("xref\n0 6\n");
BS.WriteText("0000000000 00001 f \n0000000015 00000 n \n0000000060 00000 n \n0000000111 00000 n \n0000000237 00000 n \n"+Pos1.slice(-10)+" 00000 n \n");
BS.WriteText("\ntrailer\n<</Size 6/Info<</Producer(JScrip2pdf)>>/Root 1 0 R>>\nstartxref\n"+Pos2+"\n%%EOF\n");
BS.SaveToFile("HelloWorldR&W.pdf", 2);
BS.Close();
因此,如果花足够的时间编写脚本,就有可能添加 JPEG 文件夹。
因此,我没有向 OP 提供这样的答案,因为 PowerShell 可以访问更强大的库。
因此,我将编写一个“for 循环”来将每个 JPEG 批量转换为包装的 PDF,然后在文件夹中使用 Powershell 合并,如此处所述https://stackoverflow.com/a/75524955