[[20221106151753]] 『サブフォルダー内の画像サイズを変換して保存』(Maputo) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『サブフォルダー内の画像サイズを変換して保存』(Maputo)

現在以下の作業を一つ一つ手作業で処理しているので面倒くさく時間短縮の為
作業手順をVBAで処理できませんか ?

親ホルダー内にサブフォルダーが複数存在します。
各ホルダーの中には、必ず1個のJPEGが存在します。
 (必ず1個で複数は存在しない)
そのJPEGを正方形の指定サイズ(500x500 ピクセル)にサイズ変換して元の各ホルダー内に別名で保存したい。
(元の変更前のJPEGは、そのまま残します。)

条件は、セルに指定
B2セルに、親フォルダー名(フルパス)例えば、D:\Music\Temp
B3セルに、正方形の変換サイズ指定  例えば、500

< 使用 Excel:Excel2019、使用 OS:Windows10 >


 そういうのはエクセルよりPowerShellでやったほうが楽。
 わからないことはとりあず適当に書いた記事の部分をコピペしてググってから聞いて。

 Win+Rでファイル名を指定して実行
 cmdエンター
 powershellエンター
 Set-ExecutionPolicy RemoteSigned -Scope CurrentUserエンター
 下のスクリプトをコピペしてエンター
 exitエンター
 exitエンター

 [void][Reflection.Assembly]::LoadWithPartialName("System.Drawing")
 #フォルダパスとフィルターは適当に指定
 Get-ChildItem -LiteralPath 'F:\hoge_folder' -File -Filter "*.jpg"|
 ForEach-Object{
     $image=[System.Drawing.Bitmap]::new($_.FullName)
     #サイズも変えたければ変える
     $canvas = [System.Drawing.Bitmap]::new(500, 500)
     $graphics = [System.Drawing.Graphics]::FromImage($canvas)
     $graphics.DrawImage($image, [System.Drawing.Rectangle]::new(0, 0, $canvas.Width, $canvas.Height))
     $_.DirectoryName+"\"+$_.BaseName+"_resize"+$_.Extension
     $canvas.Save($_.DirectoryName+"\"+$_.BaseName+"_resize"+$_.Extension,[System.Drawing.Imaging.ImageFormat]::Jpeg)
 }

(通りすがり) 2022/11/06(日) 16:59:43


サブフォルダーを一括で指定したい場合は
Get-ChildItem -LiteralPath 'F:\hoge_folder' -File -Filter "*.jpg"|
Get-ChildItem -LiteralPath 'F:\hoge_folder' -File -Filter "*.jpg" -Recurse|
に変えて
(通りすがり) 2022/11/06(日) 17:02:08

すいません。
達人さんはPowerShellの方が楽とはおっしゃいますが
ここはエクセルの質問所なのでEXCEL(VBA)での回答を希望します。

(Maputo) 2022/11/06(日) 17:32:05


 >現在以下の作業を一つ一つ手作業で処理しているので面倒くさく
 Excelでどのように作業しているのか、手順を説明して下さい。
  
(γ) 2022/11/06(日) 19:34:31

既存のフリーソフト使えばいいとおもうよ
縮小革命
https://netank.net/down
(トォーリス・ガリ) 2022/11/06(日) 20:45:35

縮小革命の紹介に感謝します。
試してみましたが、多層階のホルダー構造には対応していませんでした。
(希望する処理が出来ませんでした)

>Excelでどのように作業しているのか、手順を説明して下さい。

excelでは、処理していません。
ターゲットのJPEGを画像加工ソフトで画像サイズを変更する作業を
フォルダーをまたいで面倒でも続けています。

powershellでスクリプトからps1で保存して処理できました。
通りすがりさんありがとうございます。

(Maputo) 2022/11/07(月) 04:40:59


質問に回答しましたが、誰からも返事がありません。

興味が無いので回答がないので有れば諦めます。

PowerShellでの回答をくれた「通りすがり」さん、
パスをフォルダーを選択するダイアログボックスを表示して
そこからから選択できるように改造願えればありがたいです。
(スクリプト内のパスを毎回書き換えて処理しているので手抜きをしたいです)

(Maputo) 2022/11/08(火) 11:43:28


だって、Excelの質問じゃないし

>試してみましたが、多層階のホルダー構造には対応していませんでした。
フォルダをドラッグ&ドロップするとできます
(トォーリス・ガリ) 2022/11/08(火) 12:32:39


>>試してみましたが、多層階のホルダー構造には対応していませんでした。
>フォルダをドラッグ&ドロップするとできます

最初の質問で以下のように希望を伝えました。
 「そのJPEGを正方形の指定サイズ(500x500 ピクセル)にサイズ変換して元の各ホルダー内に別名で保存したい。」

「縮小革命」は、縮小したjpgをオリジナルjpgがある元のホルダー内には保存していません。
その意味で「多層階のホルダー構造には対応していない」と回答しましたが
言葉足らずで気持ちが伝わらず失礼しました。
(Maputo) 2022/11/08(火) 12:49:01


GDI+ API関数等の宣言|GDIplusCODE
http://gdipluscode.sakura.ne.jp/gdip/declare.html
画像ファイルをリサイズし、圧縮率指定でJPE保存|GDIplusCODE
http://gdipluscode.sakura.ne.jp/gdip/resize_save_jpeg.html

上記サンプルの

 >    lngWidth = lngWidth * scalerate \ 100
 >    lngHeight = lngHeight * scalerate \ 100

 ↑この部分を無理矢理↓こうして

    lngWidth = 500
    lngHeight = 500

 特に何も考えずに実行してみてもイケましたよ。
 実際にはPtrSafeとかLongPtrとか、Declare部分の見直しは必要でしょうけど。
 (私はExcel2010だしWIN64も関係ないのでそのままコピペで全く問題なかったス)

 サブフォルダを再帰的に探索するコードは当掲示板でもちょくちょく見かけます。
 (つい最近も数回あった気がする)

 まぁGDI+は「EXCEL(VBA)での回答ではない」と言われればそうかも^^;
 一応情報提供まで...

(白茶) 2022/11/08(火) 13:41:55


なるほど
出来たフォルダを元のフォルダに上書きコピーすればいいだけですけど、
そういう1アクションもしたくないわけですね
それならしょうがないですね
(トォーリス・ガリ) 2022/11/08(火) 13:45:32

PowerShellかいた通りすがりだけれど、余計なことを書きます。

ここはエクセルの質問所なのでEXCEL(VBA)での回答を希望します。

この回答にはちょっとびっくりしたし、考えさせられた。
フォルダ選択にする技術も知っているし(ググれば見つかる)、すぐ出来るけど、
エクセルVBAじゃないし、VBAからpowershell呼び出せばセーフなのかとか、
白茶さんのGDI+同様。
なにか対価貰えればすぐやるけどこの掲示板ではだめなのかな。

白茶さんも情報提供してくれているし、意地悪なのかもしれないけどMaputoさんがこんな
コードを書いてみました、みたいな誠意みたいなものがあって「やる気を刺激されれば」書くかな。

でも優しい人が作ってくれるかもしれないね。

(通りすがり) 2022/11/08(火) 14:35:10


>出来たフォルダを元のフォルダに上書きコピーすればいいだけですけど、
>そういう1アクションもしたくないわけですね

そうですね。
ファイラーを利用して縮小画像を含むフォルダーを一括して
元のフォルダーにコピペすれば良かったのですね。

頭が固くてそのアイデアは思いつきませんでした。
その手を使えばひと手間必要ですが問題なく処理できました。

(トォーリス・ガリ)さん、ありがとう。

白茶さんの貼ってくれたサイトのコードですが
 初心者の私が活用できるレベルを超えています。
(少し、ちょちょっと修正(書き直し、追加)すれば良いようなレベルでは無いです。)

(通りすがり)さん、対価は与えられそうに無いので諦めます。
Posehershellは全くわからんぽんでスクリプトを書くなど手が付けられる知識は無いです。
(少し調べてスクリプトをps1で保存してpowershellから実行すればよさそう程度の知識を得たぐらいです。)

(Maputo) 2022/11/08(火) 16:22:11


ps1はただのテキストファイルなので毎回新たに作れば。
フォルダ、ファイルの選択やテキストファイルの作成は
検索すればサンプルが見つかるし、
ps1の実行はこれとか。
【VBA】PowerShellファイルを同期実行する
https://excel-vba.work/2021/07/04/%E3%80%90vba%E3%80%91powershell%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%90%8C%E6%9C%9F%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B/
ちょちょっと修正でいけると思います。

(agt) 2022/11/08(火) 21:31:52


>ps1はただのテキストファイルなので毎回新たに作れば。

毎回作らなくとも、フォルダーのパスの部分を修正すればOKです。
「毎回新たに作れば。」が修正を含めているのであれば
すでに実行済みです。

>フォルダ、----の選択-------------は
>検索すればサンプルが見つかる

powershellについては門外漢である私でも
(通りすがり)さんのスクリプトを修正して
希望である
フォルダーのパスを選択するダイアログボックスを表示して
そこからから選択できるように相当する具体的な検索例を紹介して頂きたい。

>ちょちょっと修正でいけると思います
powershellの実行は出来ています。
「ちょちょっと修正」、powershell初心者には簡単ではないです。
(Maputo) 2022/11/09(水) 04:12:20


VBAで選択
http://officetanaka.net/excel/vba/tips/tips39.htm
修正ではなくOutputでps1の内容全体を毎回書き込んでください。
http://officetanaka.net/excel/vba/file/file08c.htm

(agt) 2022/11/09(水) 06:10:18


 >ここはエクセルの質問所なのでEXCEL(VBA)での回答を希望します。

 エクセルでも出来るってことだけで、エクセルでやろうってのが…。
 なんかずれてると思う。
 だってエクセルは画像編集ソフトじゃないし。

 >面倒くさく時間短縮の為 

 これがすべてじゃないですかね
 面倒くさいだけ。
 答える帆も面倒くさいのでは。
(ずず) 2022/11/09(水) 08:32:50

 >初心者の私が活用できるレベルを超えています
 ええ、わかってますよ。そんなの。

 >少し、ちょちょっと修正(書き直し、追加)すれば良いようなレベルでは無いです
 ...だから、何だっていうのでしょう?

 >ここはエクセルの質問所なのでEXCEL(VBA)での回答を希望します
 と「縛り」を設けたのはご自分でしょうに...

 こちらにはどうでもいい事なので普段は気に掛けずに放置するんですけど、
 よくある初心者を免罪符だと勘違いしている人ともなんかちょっと違う気がする。
 ひょっとしておちょくられてるのかな?

(白茶) 2022/11/09(水) 09:08:27


自分で処理するだけなら、すでに十分な回答が得られてるはず
たぶん作った(作ってもらった)ものを納品しないといけないのでしょう
(たぶんだけど) 2022/11/09(水) 09:14:17

色々とアドバイスを受けましが
 自分のスキル不足が原因なのですが書き込みに誤解を招く発言が多く失礼しました。

(最後は、お叱りの回答が多いので嵐と思われても心外なのでこれが最後とします。)

(白茶さん)へ
 私だけへの回答ではなく、書き込みはこのスレッドを見ている
 他の方へのアドバイス的な回答だと言うのであれば賛同できますが、
 初心者の私にレベルを超えた回答と判って書き込みされたのであれば残念です。

 >たぶん作った(作ってもらった)ものを納品しないといけないのでしょう

 この書き込みについては、全く的はずれな内容です。
  自分が使うのであって商売の為のモノではありません。
 

(Maputo) 2022/11/09(水) 11:12:15


 いやまぁ、ホント別にいいんですけど... ^^;

 何が残念なのかは全く理解できません。

 せっかくタダで入手できた情報を、
 まったく以って生かす気が無いその姿勢の方が余程残念だと思うんデスよね。

 回答した側の心情としては「じゃあ訊くなよな」って感じです。

(白茶) 2022/11/09(水) 11:30:50


 >達人さんはPowerShellの方が楽とはおっしゃいますが
 >powershellでスクリプトからps1で保存して処理できました。
 と言っておきながら
 >初心者の私にレベルを超えた回答と判って書き込みされたのであれば残念です。
 というのはおかしくないですか。
 >Posehershellは全くわからんぽんでスクリプトを書くなど手が付けられる知識は無いです。
 なのにどうして保存できたんでしょうかね。
 嘘だったんですか。
(76s) 2022/11/09(水) 11:48:19

めっちゃ叩かれてますね。
関係ない人がなんの情報も出さずに文句だけに書き込むのどうかとおもいます。
よほど暇なのでしょう、まぁ人のことは言えませんが。

なぜか刺激を受けたので勉強がてらこんなバッチを作ってみました。

準備
1.以下の”””バッチスクリプト”””をメモ帳に貼り付け
2.名前を付けて保存で名前をresize.batにする
3.文字コードをANSIにする
4.デスクトップに保存する。

使い方
リサイズしたい画像の入った”””フォルダ”””を保存したバッチファイルにドラッグ&ドロップ
 
 
 
以下バッチスクリプト、PowerShellじゃないですよ、バッチファイル、bat、拡張子がbatのやつ

 ::bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、batだよー間違えないでよー
 ::bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、batだよー間違えないでよー
 ::bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、bat、batだよー間違えないでよー

 @cd /d %1

 powershell  -ExecutionPolicy RemoteSigned -Command^
 [System.Reflection.Assembly]::LoadWithPartialName(\"System.Drawing\")^>$null;^
 Write-Host `n`n;^
 Get-ChildItem -LiteralPath ""%1"" -File -Filter \"*.jpg\" -Recurse ^|^
 ForEach-Object{^
    $image=[System.Drawing.Bitmap]::new($_.FullName);^
    $canvas = [System.Drawing.Bitmap]::new(500, 500);^
    $graphics = [System.Drawing.Graphics]::FromImage($canvas);^
    $graphics.DrawImage($image, [System.Drawing.Rectangle]::new(0, 0, $canvas.Width, $canvas.Height));^
    $_.DirectoryName+\"\\\"+$_.BaseName+\"_resize\"+$_.Extension;^
    $canvas.Save($_.DirectoryName+\"\\\"+$_.BaseName+\"_resize\"+$_.Extension,[System.Drawing.Imaging.ImageFormat]::Jpeg);^
 }

 @powershell -noexit -nologo

(通りすがり) 2022/11/09(水) 13:03:16


 もう見てないかもしれないですが・・・
 通りすがりさんに教えてもらったPowerShellの方法使って、ps1ファイルに書き込み、読込で実装してみました。
 トリミングとスケーリングがあって、そこそこ悩みました・・・
 VBAと構文違うと難しいですね。

    Option Explicit
    Enum ResizeOrder
        SCALE_ONLY = 1
        TRIM_ONLY = 2
        SCALE_and_TRIM = 3
    End Enum
    Sub リサイズテスト()
        Dim GET_USER_PARENT_DIRECTORY As String
        Dim GET_USER_RENAME As String
        Dim GET_USER_HEIGHT As Long
        Dim GET_USER_WIDTH As Long
        Dim mySETTING As ResizeOrder
        Dim fNo As Integer
        Dim i As Long
        Dim psPath As String

        'フォルダの選択
        With Application.FileDialog(msoFileDialogFolderPicker)
            If .Show = True Then
                GET_USER_PARENT_DIRECTORY = .SelectedItems(1)
            Else
                MsgBox "フォルダが選択されませんでした"
                Exit Sub
            End If
        End With

        '末尾の名前
        GET_USER_RENAME = "Resize"

        '高さの設定
        GET_USER_HEIGHT = 500

        '幅の設定
        GET_USER_WIDTH = 500

        '出力設定
        mySETTING = SCALE_and_TRIM
'        mySETTING = SCALE_ONLY
'        mySETTING = TRIM_ONLY

        'https://qiita.com/miyamiya/items/d1a975fb6618d46eda0c
        '文字コードはShiftJis(Open-PrintでShiftJis出力 メモ帳で作る場合、UTF-8注意)
        'リサイズはトリミングではなく、伸縮
        'PowerShell構文の配列列挙
        Dim ps As String
        Select Case mySETTING
            Case ResizeOrder.SCALE_ONLY
                '指定したサイズに合わせてスケーリング
                ps = ps & " Get-ChildItem -LiteralPath 'USER_PARENT_DIRECTORY' -File -Filter ""*.jpg"" -Recurse -Depth 3|" & vbCrLf                                 '指定したフォルダのサブディレクトリ「3層」までのjpgファイルを出力する
                ps = ps & " ForEach-Object{" & vbCrLf
                ps = ps & "     $image=[System.Drawing.Bitmap]::new($_.FullName)" & vbCrLf                                                                          '画像ファイル読込
                ps = ps & "     $canvas = [System.Drawing.Bitmap]::new(USER_WIDTH, USER_HEIGHT)" & vbCrLf                                                           '高さと幅の指定
                ps = ps & "     $graphics = [System.Drawing.Graphics]::FromImage($canvas)" & vbCrLf                                                                 '縮小先への描画
                ps = ps & "     $graphics.DrawImage($image, [System.Drawing.Rectangle]::new(0, 0, $canvas.Width, $canvas.Height))" & vbCrLf                         '
                ps = ps & "     $_.DirectoryName+""\""+$_.BaseName+""_USER_RENAME""+$_.Extension" & vbCrLf
                ps = ps & "     $canvas.Save($_.DirectoryName+""\""+$_.BaseName+""_USER_RENAME""+$_.Extension,[System.Drawing.Imaging.ImageFormat]::Jpeg)" & vbCrLf '保存
                ps = ps & " }" & vbCrLf
                ps = ps & "Pause"
            Case ResizeOrder.TRIM_ONLY
                '指定したサイズに合わせて、左上を基準にトリミング
                ps = ps & " Get-ChildItem -LiteralPath 'USER_PARENT_DIRECTORY' -File -Filter ""*.jpg"" -Recurse -Depth 3|" & vbCrLf
                ps = ps & " ForEach-Object{" & vbCrLf
                ps = ps & "     $image=[System.Drawing.Bitmap]::new($_.FullName)" & vbCrLf
                ps = ps & "     $TrimRect = [System.Drawing.Rectangle]::new(0, 0, USER_HEIGHT, USER_WIDTH)" & vbCrLf
                ps = ps & "     $format = $image.PixelFormat" & vbCrLf
                ps = ps & "     $graphics = $image.Clone($TrimRect, $format)" & vbCrLf
                ps = ps & "     $_.DirectoryName+""\""+$_.BaseName+""_USER_RENAME""+$_.Extension" & vbCrLf
                ps = ps & "     $graphics.Save($_.DirectoryName+""\""+$_.BaseName+""_USER_RENAME""+$_.Extension,[System.Drawing.Imaging.ImageFormat]::Jpeg)" & vbCrLf '保存
                ps = ps & " }" & vbCrLf
                ps = ps & "Pause"
            Case ResizeOrder.SCALE_and_TRIM
                '指定したサイズの内、高さに合わせてスケーリングした後、左上を基準にトリミング
                ps = ps & " Get-ChildItem -LiteralPath 'USER_PARENT_DIRECTORY' -File -Filter ""*.jpg"" -Recurse -Depth 3|" & vbCrLf
                ps = ps & " ForEach-Object{" & vbCrLf
                ps = ps & "     $image=[System.Drawing.Bitmap]::new($_.FullName)" & vbCrLf
                ps = ps & "     [int]$ScaleWidth= (USER_HEIGHT / $image.Height)" & vbCrLf '<--最初にint型指定しないと、[System.Drawing.Bitmap]の引数指定でエラーが出る
                ps = ps & "     $ScaleWidth= (USER_HEIGHT / $image.Height)" & vbCrLf
                ps = ps & "     $ScaleWidth= ($image.Width * $ScaleWidth)" & vbCrLf
                ps = ps & "     $ScaleWidth= [math]::Truncate($ScaleWidth)" & vbCrLf
                ps = ps & "     $canvas = [System.Drawing.Bitmap]::new( $ScaleWidth , USER_HEIGHT)" & vbCrLf
                ps = ps & "     $graphics = [System.Drawing.Graphics]::FromImage($canvas)" & vbCrLf                                                                 '縮小先への描画
                ps = ps & "     $graphics.DrawImage($image, [System.Drawing.Rectangle]::new(0, 0, $canvas.Width, $canvas.Height))" & vbCrLf                         '
                ps = ps & "     $TrimRect = [System.Drawing.Rectangle]::new(0, 0, USER_WIDTH, USER_HEIGHT)" & vbCrLf
                ps = ps & "     $format = $image.PixelFormat" & vbCrLf
                ps = ps & "     $ScaleTrim = $canvas.Clone($TrimRect, $format)" & vbCrLf
                ps = ps & "     $_.DirectoryName+""\""+$_.BaseName+""_USER_RENAME""+$_.Extension" & vbCrLf
                ps = ps & "     $ScaleTrim.Save($_.DirectoryName+""\""+$_.BaseName+""_USER_RENAME""+$_.Extension,[System.Drawing.Imaging.ImageFormat]::Jpeg)" & vbCrLf '保存
                ps = ps & " }" & vbCrLf
                ps = ps & "Pause"
        End Select
        '各種設定の落とし込み
        ps = Replace(ps, "USER_PARENT_DIRECTORY", GET_USER_PARENT_DIRECTORY)
        ps = Replace(ps, "USER_HEIGHT", GET_USER_HEIGHT)
        ps = Replace(ps, "USER_WIDTH", GET_USER_WIDTH)
        ps = Replace(ps, "USER_RENAME", GET_USER_RENAME)

        'PS1ファイルの書き出し
        psPath = ThisWorkbook.Path & "\resize.ps1"
        fNo = FreeFile
        Open psPath For Output As #fNo
            Print #fNo, ps
        Close #fNo

        'PS1ファイルの実行
        'https://excel-vba.work/2021/07/04/%E3%80%90vba%E3%80%91powershell%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%90%8C%E6%9C%9F%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B/
        With CreateObject("WScript.Shell")
            .Run Command:="powershell -NoProfile -ExecutionPolicy Unrestricted " & psPath, WindowStyle:=1, WaitOnReturn:=True  'ウィンドウ表示 同期実行
            '.Run Command:="powershell -NoProfile -ExecutionPolicy Unrestricted " & psPath, WindowStyle:=0, WaitOnReturn:=True 'ウィンドウ非表示 同期実行
        End With
        Kill psPath
        MsgBox "完了しました"
    End Sub

(稲葉) 2022/11/11(金) 13:24:28


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.