LoginSignup
usausa000
@usausa000

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

POWER SHELLのファイル出力先パスの書き方

解決したいこと

指定フォルダ内の画像を、EXIF情報を引継ぎつつ、圧縮したいのですが、うまくいきません。

圧縮はできているのですが、
①EXIF情報を引継ぎできていないこと。
②保存先をマイピクチャではなく任意の保存先( C:\Users\test2)か上書きをしたいです。

①は、解決につ検討もつかないのですが、②はアレコレ書き換えてみたら
エラーがばかりで進みません。

どうかお助けいただけませんでしょうか。

発生している問題・エラー

"C:\Users\test2" の値を "System.String" 型から "System.IO.Path" 型に変換できません。
発生場所 行:37 文字:5
+     [IO.Path]$destPath
+     ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) []、RuntimeException
    + FullyQualifiedErrorId : ConvertToFinalInvalidCastException
 
"2" 個の引数を指定して "Save" を呼び出し中に例外が発生しました: "GDI+ で汎用エラーが発生しました。"
発生場所 行:40 文字:1
+ $destBmp.Save($destPath, $OutFormat)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ExternalException

NameError (uninitialized constant World)

または、問題・エラーが起きている画像をここにドラッグアンドドロップ

該当するソースコード

Add-Type -AssemblyName System.Drawing

<#
.Synopsis
画像をリサイズしてマイピクチャにJpegで保存する
#>

# 元の画像ファイル
[string]$Path = "C:\Users\test1\IMG_0802.jpg"

# 変換サイズ
[double]$Scale = 0.5

# 保存形式
[Drawing.Imaging.ImageFormat]$OutFormat = [Drawing.Imaging.ImageFormat]::Jpeg


# ファイルから画像を読み込み([Drawing.Image]の方が良いけど手抜き)
[Drawing.Bitmap] $fromBmp = [Drawing.Image]::FromFile($fileName)


    # リサイズ先のビットマップを作成
    # サイズは、$sizeで指定されている倍率にする
    $toBmp = New-Object Drawing.Bitmap([int]($fromBmp.Width * $size), [int]($fromBmp.Height * $size))
    # 属性の引継ぎ(Exifや回転情報などが引き継がれるはず)
    foreach($prop in $fromBmp.PropertyItems) {
        $toBmp.SetPropertyItem($prop);
    }


# リサイズした画像
[Drawing.Bitmap]$toBmp = 
    New-Object -TypeName Drawing.Bitmap -ArgumentList $srcBmp, $newWidth, $newHeight

# 出力先のパス
[string]$destPath = 
    [IO.Path]::Combine(
        # 親フォルダ
        [Environment]::GetFolderPath([Environment+SpecialFolder]::MyPictures), 
        
        # 拡張子変更
        [IO.Path]::ChangeExtension(
            [IO.Path]::GetFileName($Path), 
            $OutFormat.ToString()
        )   
    )


# 形式指定で保存(既存ファイル上書き)
$destBmp.Save($destPath, $OutFormat)

# 結果確認
Write-Host 保存先は「 $destPath 」です。

自分で試したこと

ここに問題・エラーに対して試したことを記載してください。参考にさせてもらっている下記のサイト様の通りに
https://imihito.hatenablog.jp/entry/2018/01/13/230545

# 出力先のパス
[string]$destPath = 
    [IO.Path]::Combine(
        # 親フォルダ
        [Environment]::GetFolderPath([Environment+SpecialFolder]::MyPictures), 
        
        # 拡張子変更
        [IO.Path]::ChangeExtension(
            [IO.Path]::GetFileName($Path), 
            $OutFormat.ToString()
        )   
    )

と書けば、動くのですが、出力先がマイピクチャになってしまいます。

# 出力先のパス
[string]$destPath = "C:\Users\test1"
    [IO.Path]]$destPath

など色々書き換えてみたのですが、エラーになります。
おそらくかなり基礎的な質問で申し訳ないのですが、教えて頂けませんでしょうか。
※できればこのソースをVBAから呼び出しして実行させたいと思っています。

EXIF情報については、下記のサイトを参考にさせて頂いております。
https://take4-blue.com/program/powershell/powershell%ef%bc%8d%e7%94%bb%e5%83%8f%e3%81%ae%e4%b8%80%e6%8b%ac%e3%83%aa%e3%82%b5%e3%82%a4%e3%82%ba/

0

2Answer

蛇足ですが、パス操作のテクニックを一つ

パスの処理はSystem.IO.FileInfo型にしておくと便利です。
たとえば、$Path変数にはフルパスで記述されているので

$info = gp $Path    # gp はGet-ItemPropertyのエイリアス

$info.BaseName      # 拡張子を除いたファイル名
$info.Extension     # 拡張子(ドット含む)
$info.Name          # 拡張子を含むファイル名
$info.FullName      # フルパス
$info.DirectoryName # 親フォルダのフルパス

な感じでファイルパスの要素が簡単に取れます。

これを使うと、

# 文字列で変数展開する場合、必要なら自動的にToString()を補ってくれる
# なので、$OutFormat.ToString()と書かなくてもOK
$destPath = "C:\Users\test1\$($info.BaseName).$($OutFormat)"

と簡易に書けます。

0

Comments

  1. @usausa000

    Questioner
    ありがとうございます。何時間も悩んでいたのに、こんなにすっきり解決してくださり助かりました。またぜひよろしくお願いいたします

基本方針に変わりはなく、

[string]$destPath = [IO.Path]::Combine(
    "C:\Users\test1", 
    [IO.Path]::ChangeExtension([IO.Path]::GetFileName($Path), $OutFormat.ToString())
)

です。

もしくは、そのまま文字列で組み立ててもよいです。

$dir = "C:\Users\test1"
$imgName = [IO.Path]::ChangeExtension([IO.Path]::GetFileName($Path), $OutFormat.ToString())

$destPath = "${dir}\${imgName}"

上では、変数に入れましたが、subexpression演算子($())を使えばインラインに記述もできます。

$destPath = "C:\Users\test1\$([IO.Path]::ChangeExtension([IO.Path]::GetFileName($Path), $OutFormat.ToString()))"

お好きな方法をどうぞ。

0

Comments

  1. @usausa000

    Questioner
    ありがとうございます。インライン記述助かりました。一行ずつしかVBAで呼び出せなかったので。なんとか形になりそうです。お二人とも回答くださりありがとうございました。

Your answer might help someone💌