簡體   English   中英

在 Windows 7 中遞歸修復圖像文件擴展名

[英]Recursively fixing image file extensions in Windows 7

希望這是一個快速而簡單的問題......

我和這個用戶有同樣的問題: https ://superuser.com/questions/812455/recursively-fixing-image-file-extensions-in-linux 除了我使用的是 Windows (7) 機器。 (大多數軟件都忽略了 BlamKiwi 提到的擴展,但我經常遇到 Adob​​e 軟件的問題。)

我問的是 SO 而不是 SU,因為我只需要一些幫助將“最佳答案”代碼翻譯成可以在我的機器上運行的東西。

for f in *.{jpg,JPG,png,PNG,jpeg,JPEG}; do 
    type=$( file "$f" | grep -oP '\w+(?= image data)' )
    case $type in  
        PNG)  newext=png ;; 
        JPEG) newext=jpg ;; 
        *)    echo "??? what is this: $f"; continue ;; 
    esac
    ext=${f##*.}   # remove everything up to and including the last dot
    if [[ $ext != $newext ]]; then
        # remove "echo" if you're satisfied it's working
        echo mv "$f" "${f%.*}.$newext"
    fi
done

我猜一個 .batch 文件可以做到這一點,但不知道自己編寫它。

IrfanView是一個免費軟件(供私人使用)多媒體查看器,如果圖像文件的文件擴展名不適合圖像格式,默認情況下會在查看圖像文件時顯示一個消息框,提示用戶重命名文件以更正文件擴展名。 可以在配置中禁用此消息提示,但在查看圖像文件時檢測文件擴展名錯誤的圖像文件非常有用。

便攜式網絡圖形格式的圖像始終以 4 字節89 50 4E 47 (十六進制)開頭,在使用代碼頁 437 (北美)或代碼頁 850 (西歐)作為ëPNG時,它們會顯示在命令提示符窗口中。

JPEG 文件交換格式的圖像以 10 字節FF D8 FF E0 s1 s2 4A 46 49 46開頭。 這 10 個字節中的最后 4 個字節是JFIF s1 s2作為長度信息是可變的。

命令FINDSTR設計用於搜索文本文件中的字符串,但也可用於搜索二進制文件中的字符串。 這由下面的批處理文件使用:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "MessageOutput="
for /F "delims=" %%I in ('dir *.jpg *jpeg *.png /A-D /B /ON 2^>nul') do (

    %SystemRoot%\System32\findstr.exe /M /C:PNG "%%I" >nul
    if errorlevel 1 ( set "IsPNG=" ) else set "IsPNG=1"

    %SystemRoot%\System32\findstr.exe /M /C:JFIF "%%I" >nul
    if errorlevel 1 ( set "IsJPG=" ) else set "IsJPG=1"

    if defined IsPNG if defined IsJPG (
        set "FirstPNG=1"
        for /F "delims=:" %%J in ('%SystemRoot%\System32\findstr.exe /N /C:PNG "%%I"') do (
            if defined FirstPNG (
                if "%%J" == "1" ( set "IsJPG=" ) else set "IsPNG="
                set "FirstPNG="
            )
        )
    )

    if defined IsPNG (
        if /I not "%%~xI" == ".png" (
            echo PNG image "%%I" has wrong file extension.
            ren "%%I" "%%~nI.png"
            set "MessageOutput=1"
        )
    ) else if defined IsJPG (
        if /I "%%~xI" == ".png" (
            echo JPG image "%%I" has wrong file extension.
            ren "%%I" "%%~nI.jpg"
            set "MessageOutput=1"
        )
    ) else (
        echo/
        echo ERROR: File "%%I" is neither a JPG nor a PNG file.
        echo/
        set "MessageOutput=1"
    )
)
if defined MessageOutput (
    echo/
    pause
)
endlocal

命令DIR由命令FOR在后台的單獨命令進程中執行,以獲取 *.jpg、*.jpeg 和 *.png 文件名的列表,而在執行批處理文件時不包含當前目錄中的文件路徑。

閱讀有關使用命令重定向運算符的 Microsoft 文章,了解2>nul的說明。 重定向運算符>必須在FOR命令行上使用脫字符^進行轉義,以便在 Windows 命令解釋器在執行命令FOR之前處理此命令行時解釋為文字字符,該命令使用在后台啟動的單獨命令進程執行嵌入式dir命令行。

這里有必要使用命令DIR而不是使用

for %%I in (*.jpg *jpeg *.png) do (

因為DIR輸出的列表,由FOR逐行捕獲和處理,在循環迭代期間不再更改。 這在這里很重要,因為可能會由於重命名操作而更改當前目錄中的文件條目列表。 通過直接使用FOR ,在文件重命名后可能會發生文件被處理兩次或目錄中的另一個文件由於循環迭代期間目錄列表更改而被跳過的情況。

編寫代碼是為了避免使用延遲的環境變量擴展,也適用於帶有感嘆號的文件。 使用子例程也可以實現不同的解決方案。

對於DIR找到的每個文件,首先對文件執行區分大小寫的PNG搜索,並在文件中找不到環境變量IsPNG或在包含PNG的文件上定義為值1時刪除環境變量 IsPNG。

接下來對文件執行區分大小寫的JFIF搜索,並在文件中找不到環境變量IsJPG或在包含JFIF的文件上使用值1定義環境變量 IsJPG。

圖像文件的二進制數據可能包含數據中的任何位置,也可能包含十六進制字節序列50 4E 474A 46 49 46 第三個IF命令行檢查文件是否包含兩個字節序列。 在這種罕見的情況下,再次執行查找PNGFINDSTR並評估在哪個“行”中找到了字符串。 如果行號是1 ,那么字符串PNG肯定在文件的頂部,這非常清楚地表明該文件是 PNG 文件,否則它應該是一個包含字節50 4E 47的 JPEG 文件。 批處理代碼處理的最壞情況是在標頭和數據PNGJFIF中包含PNG的 PNG 圖像文件,它只需要評估FINDSTR找到的第一次出現的PNG

如果當前圖像文件(很可能)是 PNG 文件,但沒有預期的文件擴展名.png ,則會輸出適當的消息並重命名文件(不檢查是否成功)。 對於 *.png 文件(很可能)是 JPEG 文件,會輸出類似的消息,並執行文件重命名以更改文件擴展名。

擴展名為.png.jpg.jpeg的文件也可能既不包含PNG也不包含JFIF ,例如作為 GIF 文件。 在這種情況下,將輸出錯誤消息,因為此批處理代碼無法確定圖像格式。

如果輸出任何消息,批處理文件執行將在結束時停止。 這意味着雙擊批處理文件時,如果所有 *.jpg、*.jpeg 和 *.png 文件根據圖像格式具有正確的文件擴展名,則會出現控制台窗口並關閉。

當然,這個解決方案絕對不是完美的。 第一行包含PNG ,第二行包含JFIF且文件擴展名為.jpg的文本文件將被解釋為 PNG 圖像文件,盡管它實際上是一個文本文件。 IrfanView絕對是真正檢查 *.jpg、*.jpeg 或 *.png 文件是否真的是 JPEG 或 PNG 圖像文件的更好選擇。

這里還有一個使用子程序的替代解決方案:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "MessageOutput="

for /F "delims=" %%I in ('dir *.jpg *jpeg *.png /A-D /B /ON 2^>nul') do call :CheckImage "%%I"

if defined MessageOutput (
    echo/
    pause
)
endlocal
goto :EOF


:CheckImage
set "IsJPG=0"
set "IsPNG=0"

%SystemRoot%\System32\findstr.exe /M /C:PNG %1 >nul
if not errorlevel 1 set "IsPNG=1"

%SystemRoot%\System32\findstr.exe /M /C:JFIF %1 >nul
if not errorlevel 1 set "IsJPG=1"

if %IsPNG% == 1 if %IsJPG% == 1 (
    for /F "delims=:" %%J in ('%SystemRoot%\System32\findstr.exe /N /C:PNG %1') do (
        if "%%J" == "1" ( set "IsJPG=0" ) else set "IsPNG=0"
        goto CheckExtension
    )
)

:CheckExtension
if %IsPNG% == 1 (
    if /I not "%~x1" == ".png" (
        echo PNG image %1 has wrong file extension.
        ren %1 "%~n1.png"
        set "MessageOutput=1"
    )
    goto :EOF
)

if %IsJPG% == 1 (
    if /I "%~x1" == ".png" (
        echo JPG image %1 has wrong file extension.
        ren %1 "%~n1.jpg"
        set "MessageOutput=1"
    )
    goto :EOF
)

echo/
echo ERROR: File %1 is neither a JPG nor a PNG file.
echo/
set "MessageOutput=1"
goto :EOF

要了解使用的命令及其工作原理,請打開命令提示符窗口,在其中執行以下命令,並仔細閱讀每個命令顯示的所有幫助頁面。

  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • if /?
  • pause /?
  • ren /?
  • set /?
  • setlocal /?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM