[[20140108105535]] 『ペイントを開いて伸縮と傾きを変更』(あや) ページの最後に飛ぶ

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

 

『ペイントを開いて伸縮と傾きを変更』(あや)

●やりたいこと

フォルダに入ったJPGファイルの画像の大きさを変更させたく
複数のJPGファイルがあるため、マクロで自動化したい

●かんがえたこと

JPGファイルをペイントで開いて、
[変形]-[伸縮と傾き]を指定する
(指定サイズはセルに入力して変数で渡すか
 フォームのテキストボックスに入力を求めるかにします)

●つくりかけているもの

Option Explicit

Sub SubStart()

    Dim StrFPath As String
    Dim Fbuf As String

    Application.ScreenUpdating = False

    StrFPath = Sheet3.Lblフォルダ指定.Caption

    Fbuf = StrFPath & "\" & Dir(StrFPath & "\" & "*")

    Do While Fbuf <> StrFPath & "\"

        Open Fbuf For Input As #1

☆画像が開いてきません

        Fbuf = StrFPath & "\" & Dir()

    Loop

    Application.ScreenUpdating = True

End Sub

●問題

☆のところで、画像が開いてきておらず
2回目のLoppに入ってから
Open Fbuf For Input As #1のところで
「実行時エラー 55 ファイルは既に開かれています」となります

なにがどのようにできるのかわからずにもやもやしながら作っていて
ペイントで開けたらSendkeysを使おうかなと考えていたりするのですが…

半端な感じの質問になってしまい、すみません。
根本的にもっと別の方法があるよ、などもありましたら教えてください

< 使用 Excel:Excel2013、使用 OS:WindowsXP >


 縮小専用。 
http://i-section.net/software/shukusen/

 こういうソフトがフリーでありますが、足りないですか?
(稲葉) 2014/01/08(水) 11:12

稲葉さん ありがとうございます

会社内での作業になるのですが
社内にフリーソフトが入れられないため
VBAの対応を考えております

(あや) 2014/01/08(水) 11:17


小さくしたいのは、ファイルサイズですか? 表示サイズですか?

表示だけ小さくするならば、解像度情報だけバイナリ変更すれば、画素数は
そのままで、見た目だけ小さくする方法が使えます。

ファイルサイズ自体を小さくするならば、ActiveSheet.Pictures.Insertを使って
シート上に画像貼付け後、拡大率を変更(Excel上で縮小してしまう)、コピー、
クリップボード経由でペイント等で保存、とかでしょうか。

ペイントブラシ操作が面倒であれば、画像縮小後にWebページ(html)として保存し、
出力されたファイルの中から画像を拾う、とか?
(???) 2014/01/08(水) 11:42


 こんにちは。

 WIAの機能を使用してはどうでしょうか。

 Function ImgScaleChange( _
          ByVal LoadFile As String, _
          ByVal SaveFile As String, _
          ByVal MaxWidth As Long, _
          ByVal MaxHeight As Long) As Boolean

   Dim Img As Object
   Dim IP As Object

   Set Img = CreateObject("WIA.ImageFile")
   Set IP = CreateObject("WIA.ImageProcess")

   If Len(Dir(LoadFile)) <> 0 And Len(Dir(SaveFile)) = 0 Then
     Img.LoadFile LoadFile

     IP.Filters.Add IP.FilterInfos("Scale").FilterID
     IP.Filters(1).Properties("MaximumWidth") = MaxWidth
     IP.Filters(1).Properties("MaximumHeight") = MaxHeight

     Set Img = IP.Apply(Img)
     Img.SaveFile SaveFile
     ImgScaleChange = True
   End If

   Set IP = Nothing
   Set Img = Nothing
 End Function

 MaxiWidthとMaxHeightに指定した値の範囲内で縦横の比が保持された画像が作成されます。
 上書き保存はできません。

(ちび坊主) 2014/01/08(水) 14:03


???さんちび坊主さん ありがとうございます

???さんありがとうございます
見た目のサイズとファイルサイズも小さくしようと思っています。

ちび坊主さんに教えて頂いた方法をためしてみました。
Private Sub CmdStart_Click()

    Fpass1 = "C:\画像フォルダ\1無題.JPG"
    Fpass2 = "C:\画像フォルダ\1無題2.JPG"

    Call ImgScaleChange(Fpass1, Fpass2, 10, 10)

End Sub

Function ImgScaleChange( _

          ByVal LoadFile As String, _
          ByVal SaveFile As String, _
          ByVal MaxWidth As Long, _
          ByVal MaxHeight As Long) As Boolean

   Dim Img As Object
   Dim IP As Object

   Set Img = CreateObject("WIA.ImageFile")   ☆
   Set IP = CreateObject("WIA.ImageProcess")

  (省略)

 End Function

☆のところで 
「実行時エラー429 ActiveXコンポーネントはオブジェクトを作成できません」
となります。

ファイルのパスは間違っていないのです

確認方法や試してみたらよいことなどありましたら教えてください。
(あや) 2014/01/08(水) 15:59


 こっちも地道に調べて作ってみた。
 1、図の挿入で、一括処理したい図を一つのシートに貼り付ける
 2、図が挿入されているシートを選択して、サイズ変更を実行する
 3、図を挿入したブックの保存先に裸で「jpeg」の画像だけ出力される

 '==ここから
Option Explicit
Dim Target As String
Dim colItem As New Collection
Sub サイズ変更()
    Dim W As Integer
    Dim objSP As Shape
    Dim strZIP As String
    On Error Resume Next
    W = CInt(InputBox("変更したいサイズの横幅を入力してください", , 640))
    If Err > 0 Then MsgBox ("数値で入力してください"): Exit Sub
    On Error GoTo 0
    For Each objSP In ActiveSheet.Shapes
        With objSP
            .LockAspectRatio = True
            .Width = W
            .Cut
        End With
        ActiveSheet.PasteSpecial Format:="図 (JPEG)"
    Next
    strZIP = ThisWorkbook.Path & "\test.zip"
    ThisWorkbook.SaveCopyAs strZIP
    Target = "jpeg"
    Call 画像取得(strZIP, ThisWorkbook.Path & "\")
    MsgBox ("画像をこのブックの保存先に保存しました。")
End Sub
Sub 画像取得(ByVal strGetPath As Variant, ByVal strOutPath As Variant)
    Dim objFolder
    Dim c As Object
    Target = "jpeg"
    With CreateObject("Shell.Application")
        Set objFolder = .Namespace(strGetPath)
        Call GETZIP(objFolder.Items())
        Set objFolder = .Namespace(strOutPath)
        For Each c In colItem
            objFolder.CopyHere c
        Next
    End With
    Set objFolder = Nothing
End Sub
Sub GETZIP(tmpF)
    Dim tmpI As Object
    For Each tmpI In tmpF
        With tmpI
            If tmpI.IsFolder Then
                Call GETZIP(tmpI.GetFolder.Items())
            Else
                If tmpI.Name Like "*" & Target Then
                    colItem.Add tmpI
                End If
            End If
        End With
    Next
End Sub
 '==ここまで

 この場を借りて質問・・・
 Shell.ApplicationのNameSpaceで、String型の変数で値を渡すと、Nothingになってしまいました。
 変数の型をVariantにして引数を渡すと大丈夫だったのですが、Shell.Applicationに渡す型はVariant
 じゃないとだめなんですかね?

(稲葉) 2014/01/08(水) 16:35


 参照設定で、Microsoft Windows Acquisition Libraryはあるでしょうか。
 これがなければ、WIAがインストールされてない恐れがあります。
 その場合は、この手法はあきらめてください。

 あれば、参照設定でチェックを入れて、CreateObjectの代わりに、Newキーワードで

 Set Img = New WIA.ImageFile
 Set IP = New WIA.ImageProcess

 としてみてはどうでしょうか。
(ちび坊主) 2014/01/08(水) 16:42

ちび坊主さんのサンプルを実行するには、WIA(Windows Imaging Acquisition)が必要。
しかしXPにはWIAがインストールされていないので、自分でライブラリをインストールする必要あり。

なお、ダウンロードするURLリンクが切れていたので、いまはどれをインストールするのか判らず。
ドライバ開発SDK等を入れないと駄目なのだろうか? それはちょっと…。
(私の使っているXPには入っているので、何かのついでにインストールされる模様)
(???) 2014/01/08(水) 17:03


 稲葉さん ちび坊主さん ???さんありがとうございます

 ちび坊主さん???さんの教えてくださった
 Microsoft Windows Acquisition Library
 が見当たらないため…;д;

 今現在、稲葉さんの方法で進めさせていただいております

 (挿入-図-ファイルから で図の挿入をしなくても良いように
 フォルダを指定するよう付け加えました)

 Option Explicit
 Dim Target As String
 Dim colItem As New Collection

 Public Sub Subサイズ変更()
    Dim W As Integer
    Dim objSP As Shape
    Dim strZIP As String

    On Error Resume Next

    Dim StrFPath As String
    Dim Fbuf As String

    W = CInt(InputBox("変更したいサイズの横幅を入力してください", , 640))

    If Err > 0 Then MsgBox ("数値で入力してください"): Exit Sub
    On Error GoTo 0

    Application.ScreenUpdating = False

    StrFPath = Sheet3.Lblフォルダ指定.Caption

    Fbuf = StrFPath & "\" & Dir(StrFPath & "\" & "*")

    Do While Fbuf <> StrFPath & "\"

        ActiveSheet.Pictures.Insert(Fbuf).Select

        For Each objSP In ActiveSheet.Shapes
            With objSP
                .LockAspectRatio = True '指定した図形のサイズを変更しても元の比率が保持される
                .Width = W
                .Cut
            End With
            ActiveSheet.PasteSpecial Format:="図 (JPEG)"
        Next

        Fbuf = StrFPath & "\" & Dir()

    Loop

    strZIP = ThisWorkbook.Path & "\test.zip"
    ThisWorkbook.SaveCopyAs strZIP
    Target = "jpeg"

    Call 画像取得(strZIP, ThisWorkbook.Path & "\")

    MsgBox ("画像をこのブックの保存先に保存しました。")

    Application.ScreenUpdating = True

 End Sub

 おかげさまで
 このプログラムで最後まで進めるのですが
 保存できたZIPをダブルクリックすると
 「圧縮(zip形式)フォルダは無効であるか、または壊れています」となり
 開けることができません。

    strZIP = ThisWorkbook.Path & "\test.zip"
 の部分にブレークポイントを置いてデバッグをすると
 「中断モードでは入力できません」と出てしまい
 どのように確認・対処すればよいかわからなくなっています。

 なんどもすみませんが、アドバイスよろしくおねがいします。

(あや) 2014/01/09(木) 11:14


 横から失礼しますが、
 ThisWorkbook.SaveCopyAs strZIP
 は無茶な気がします。

 EXCEL は ZIP フォーマットで保存できませんので、いったん通常のファイル形式で保存し、
 圧縮処理は別にする必要があると思います。

 検索すればいろいろあると思いますが、検索結果の一例まで。
http://scripting.cocolog-nifty.com/blog/2007/11/vbazip_a144.html
(Mook) 2014/01/09(木) 11:31

 返事が遅くなりました。
 Mookさん
 >ThisWorkbook.SaveCopyAs strZIP
 >は無茶な気がします。
 私も無茶だと思っていますが、ご存知の通り2007以降の保存形式ならば、
 例えば「test.xlsx」を「test.xlsx.zip」にリネームすることで、画像を取り出せることを利用して、
 「ZIP形式で圧縮」が目的ではなく、「ZIPの拡張子にりネームして、エクスプローラで開く」が目的
 になります。

 なので
 >EXCEL は ZIP フォーマットで保存できませんので、いったん通常のファイル形式で保存し、
 >圧縮処理は別にする必要があると思います。
 これだと、ZIPファイルの中にエクセルファイルがあるだけなので、意味がないのです。
 (たぶん)

 あやさん
 使用しているエクセルは2013ですよね?
 マクロが保存されているブックの形式はxlsmではなくxlsになっていませんか?
 xlsm形式に変換してもう一度試してみてください。
(稲葉) 2014/01/10(金) 09:49

 >例えば「test.xlsx」を「test.xlsx.zip」にリネームすることで、画像を取り出せることを利用して、
 言われてみると、そういう話があったような気がしますが、それは標準仕様ではなくて、
 フォーマットが XML に変わったことの副作用的なものなので、通常の機能とは思わない
 方が良い気がします。

 ただ、上記であれば、xlsx(もしくはxlsm)形式で(SaveCopyAsで)保存して、名前を変える
 という処理にすれば良いのではないでしょうか。

 最初から Save で名前とフォーマットを指定すればできるかもしれませんが、確認してい
 ないので「おそらくこうだろう」という話ですが。
(Mook) 2014/01/10(金) 13:06

 稲葉さん、なんどもありがとうございます。

 ややこしくて申し訳ないのですが
 2010はクラウドシステムで動いております。

 xlsmにすることはできたのですが
 実行すると
 「(指定フォルダ)は読み取り専用です。アクセスできません」となりました

 あまりよくわかっていないのですがクラウドのせいかと思うのですが…
 知識が無いのでどうもできずにいます-д-;

 Mookさん、ありがとうございます。
 おっしゃってることはなんとなくわかったつもりです
 >通常の機能とは思わない方が良い気がします。
 ここはよく覚えておきます。
(あや) 2014/01/10(金) 13:23

 >〜〜それは標準仕様ではなくて、
 >〜〜通常の機能とは思わない
 >方が良い気がします。
 肝に銘じておきます。

 >ただ、上記であれば、xlsx(もしくはxlsm)形式で(SaveCopyAsで)保存して、名前を変える
 >という処理にすれば良いのではないでしょうか。
 めんどくさかったのと、出来てしまったのでコードサボりました。
 すみません。

 あやさん
 すみませんが、今回は出来る出来ないだけで、あやさんが使う・使わないを選択して頂ければ
 ありがたいです。
 なので、使用したことによるあらゆる弊害は、マイクロソフト社はございません、と付け加え
 させてください。

 書き直しますので少々お時間ください。
 またCドライブ直下はアクセスできますか?

(稲葉) 2014/01/10(金) 15:17


 保存したい場所をstrPTに入れてください。(最後の\はなし)
 Sheet3はOption Explicit入れておくと、定義されてないって怒られたので変更しました。
 .Pictures.Insertメソッドは、2010から仕様が変わっているようなので、
 .Shapes.AddPictureメソッドに直しました。
 あとはNameステートメントとKillステートメントで細かい処理しました。

 全部差し替えです。
Option Explicit
Dim colItem As New Collection
Const strPT As String = "C:\エクセルの学校"
Const strFN As String = "test"
Const Target As String = "jpeg"
Public Sub サイズ変更2()
    Dim W As Integer
    Dim objSP As Shape
    Dim StrFPath As String
    Dim Fbuf As String
    Dim strZIP As String
    Dim strXLM As String
    '==サイズ指定
    On Error Resume Next
    W = CInt(InputBox("変更したいサイズの横幅を入力してください", , 640))
    If Err > 0 Then MsgBox ("数値で入力してください"): Exit Sub
    On Error GoTo 0
    '==変数設定
    StrFPath = Sheets("Sheet3").Lblフォルダ指定.Caption
    Fbuf = StrFPath & "\" & Dir(StrFPath & "\" & "*")
    strZIP = strPT & strFN & ".zip"
    strXLM = strPT & strFN & ".xlsm"
    '==画像の挿入及びサイズ変更
    Application.ScreenUpdating = False
    With ActiveSheet
        .Shapes.SelectAll
        Selection.Delete
        Do While Fbuf <> StrFPath & "\"
            Set objSP = .Shapes.AddPicture(Fbuf, False, True, 0, 0, 0, 0)
            With objSP
                .ScaleHeight 1!, msoTrue
                .ScaleWidth 1!, msoTrue
                .LockAspectRatio = True '指定した図形のサイズを変更しても元の比率が保持される
                If .Width < .Height Then
                    .Height = W
                Else
                    .Width = W
                End If
                .Cut
            End With
            .PasteSpecial Format:="図 (JPEG)"
            Fbuf = StrFPath & "\" & Dir()
        Loop
    End With
    '==ファイルをxlsmで保存
    ThisWorkbook.SaveCopyAs strXLM
    '==.zipにリネーム
    Name strXLM As strZIP
    '==画像をzupから取り出す(Not標準機能)
    Call 画像取得(strZIP, strPT)
    '==作ったファイルを消す
    Kill strZIP
    Application.ScreenUpdating = True
    MsgBox ("画像を" & strPT & "に保存しました。")
End Sub
Private Sub 画像取得(ByVal strGetPath As Variant, ByVal strOutPath As Variant)
    Dim objFolder
    Dim c As Object
    With CreateObject("Shell.Application")
        Set objFolder = .Namespace(strGetPath)
        Call GETZIP(objFolder.Items())
        Set objFolder = .Namespace(strOutPath)
        For Each c In colItem
            objFolder.CopyHere c
        Next
    End With
    Set objFolder = Nothing
End Sub
Private Sub GETZIP(tmpF)
    Dim tmpI As Object
    For Each tmpI In tmpF
        With tmpI
            If tmpI.IsFolder Then
                Call GETZIP(tmpI.GetFolder.Items())
            Else
                If tmpI.Name Like "*" & Target Then
                    colItem.Add tmpI
                End If
            End If
        End With
    Next
End Sub
(稲葉) 2014/01/10(金) 18:00

 > >〜〜それは標準仕様ではなくて、
 > >〜〜通常の機能とは思わない
 > >方が良い気がします。
 > 肝に銘じておきます。

 えらい素直ですね。
 テストして問題ないと確認したのなら、回り道しなければならない理屈か私には分からないです。
 逆算すれば、標準仕様がファイル名はユーザーの指定に従うと云うことなんじゃないですか?
 それは言い過ぎ? 
 しかし、少なくともZIPに関しては旨く行っても私は何の違和感もないです。
 今のエクセルファイルはZIPファイルなんですから。

(半平太) 2014/01/10(金) 19:34


 半平太さん
 確かにテストして問題ないの確認しております。
 .txtも.batや.htmlに書き換えられたのでいいのかなーってな具合でやっちゃってたので
 先生方に違うんじゃない?って言われたらそうなのかーと思ってしまいます。
 間違えや勘違いが多いので・・・
 2行増えただけですし、別にいいかな?とも・・・

 それよりも、作り終えた後のテストで、「ファイルがあります」エラーを調べたら
 「CopyHere メソッドから Zip ファイルを処理することはできません」
http://support.microsoft.com/kb/2679832/ja

 こっちのほうが問題なんじゃないかと・・・
 これも「できちゃったから」OK?

(稲葉) 2014/01/10(金) 21:03


 うーん、私の知識が不足していた?
http://pc.nikkeibp.co.jp/article/NPC/20060629/242158/
 結構一般的な周知の事実だったでしょうか。
(Mook) 2014/01/10(金) 22:09

 > こっちのほうが問題なんじゃないかと・・・
 > これも「できちゃったから」OK?

 こっちはそうも行かなそうですね ^^

 言われてみると、ZIPファイルからなんか取り出すのって、
 危なっかしーからサポート対象外になってもしょうがないかも知れないです。

 そうなると、Webページの発行ですかね?

(半平太) 2014/01/10(金) 23:01


なんか面白いことやってますねぇ。
自分もhtmlで保存の方がお手軽かなぁと思ってます。

稲葉さんの質問は
.Namespace(strGetPath)を.Namespace((strGetPath))にしてみたらどうなりますか?
あとstringでもconstなら大丈夫だった気がするので、
値を渡さずそのまま使えばいいような予感がします。
(特に試してないので的外れだったらスルーしてください)
(日捲り熊五郎) 2014/01/11(土) 00:34


 htmlで試してみましたが、全部pngに。
 2003使っていた時はjpgで保存出来ていた気がするのですが・・・。

 日捲り熊五郎さん
 ありがとうございます。
 試してみて動くようになりました。
 Namespace側の引数の型が違っていたので、強制的に値を渡す必要があったってことですよね?
http://msdn.microsoft.com/ja-jp/library/chy4288y.aspx

(稲葉) 2014/01/14(火) 09:25


 すみません ついていけてなくて^^;

 htmlの保存のほうがよいのかな?
 でもせっかく作っていただいたのでサイズ変更2試しておりました
 パスまでこちらの環境に合わせて
 設定してくださりありがとうございます

 動かしてみたところ
 作業は終了した感じなのですが
 画像サイズは小さくなっておりません

 わからないなりに確認したこと

 Const strPT As String = "C:\画像"
 にしました

 '==ファイルをxlsmで保存
 ThisWorkbook.SaveCopyAs strXLM

 →C:\ に 画像test.xlsmが作られる
  ちなみに、エクセル2010クラウドの環境で開こうとすると
 「Excelファイル'画像test.xlsm'を開くことができません。
  ファイル形式またはファイル拡張子が正しくありません。
  ファイルが破損しておらず、ファイル拡張子とファイル形式が一致していることを確認してください。」
  というエラーメッセージが出ます

 そのまま進めて

 '==.zipにリネーム
 Name strXLM As strZIP

 →C:\ に 画像test.zipが作られる
  ダブルクリックすると
  「圧縮(Zip形式)フォルダは無効であるか、または壊れています」
  というエラーメッセージが出ます

 '==画像をzupから取り出す(Not標準機能)
 Call 画像取得(strZIP, strPT)

 この中の
 Call GETZIP(objFolder.Items())で
 objFolder.Items()に何も入っていない状態で
 GETZIP(tmpF)に進んでいるのですが

 なにか使い方が間違っていますでしょうか?

 またなにかありましたら、アドバイスよろしくおねがいします。

 話しに入れていませんが必死に読んでいますので^^;
(あや) 2014/01/14(火) 11:32

 再現できなーい!
 ブックのバージョンがどうなっているのか気になるので、同じブックに↓を入れて、でてきた数値を
 教えてください。
Sub BookF()
    MsgBox (ThisWorkbook.FileFormat)
End Sub
(稲葉) 2014/01/14(火) 12:03

 稲葉さんありがとうございます

 -4143 になりました

 すみません。実際
 objFolder.Items()
 には、何が入ってくるものなのでしょうか?

(あや) 2014/01/14(火) 12:16


 objFolder.Items()は後述します。

 まず先ほど調べてもらった「-4143」は定数xlWorkbookNormalのことです。

http://july.dyndns.info/varietywiki/index.php?%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%2FExcel%20VBA

 【引用ここから】
 FileFormat パラメータに xlWorkbookNormal を指定すると、Excel のバージョンに依存せず、常に Excel 97-2003 の互換ブックとして保存します。
 【ここまで】

 ということですので、
http://www.relief.jp/itnote/archives/013957.php
 こちらを参考に、xlsmに「変換」してから試してください。

 objFolder.Items()は、Shell.Applicationのnamespaceメソッドでフォルダオブジェクトを作り、
 itemsメソッドでファイルのオブジェクトを入れています。
 ファイルが複数ある場合は、()とすることでオブジェクトのコレクション(でいいのかな)を
 引数として渡しています。

 なので、イミディエイトウィンドウで()に数値を入れてnameプロパティなどでどの番号にどの
 ファイルオブジェクトが当てはめられているか確認してみてください。

(稲葉) 2014/01/14(火) 12:54


 少しずつ理解しようとしていたところだったんですが
 依頼していた人から、必要なくなりましたとの言葉

 完成するまで作りたかったのですが
 時間的な問題でさわれなくなってしまいました。
 また合間見て質問させてもらうことがありましたら
 よろしくおねがいしますm(__)m

 せっかくお時間頂いたのに、すみません。
 ありがとうございました
(あや) 2014/01/22(水) 10:01

コメント返信:

[ 一覧(最新更新順) ]


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