Imports OfficeImageReducer.ClassMyCommon ''ClassMyConmonのプロパティ・メソッドを参照するためのImportsステートメント
Imports System.IO
Imports System.IO.Compression
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices

''' <summary>メイン(スタートアップ)フォーム</summary>
Public Class FormMain

    Private Sub FormMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        On Error Resume Next

        Log.Put("終了" + vbCrLf)
        Log.Save()

    End Sub

    ''' <summary>メイン(スタートアップ)フォームのロード</summary>
    ''' <param name="sender">イベントを発生させたオブジェクト</param>
    ''' <param name="e">イベントオプション</param>
    Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

#If 0 Then
        ''多重起動チェック
        'Process.GetProcessesByName メソッド
        '指定したプロセス名を共有するリモートコンピュータ上の
        'すべてのプロセスリソースに関連付けます。
        Dim pn As String = Process.GetCurrentProcess.ProcessName 'Process.ProcessName プロパティ(プロセスの名前を取得します)
        If Process.GetProcessesByName(pn).GetUpperBound(0) > 0 Then
            ''多重起動しているならばエラーメッセージ表示して終了。
            MessageBox.Show("すでに起動しています。", TITLE + " エラーメッセージ", _
                MessageBoxButtons.OK, _
                MessageBoxIcon.Error)
            End
        End If
#End If
        frmMain = Me

        FormControlBoxCustomize(Me)

        Me.Text = TITLE + " " + VERSION

        Log = New ClassLog(Me.TextBox4)

        Log.DebugPut("起動しました。" + vbCrLf)

        Button4.PerformClick()

        '起動時は最前面にもってくる
        Me.Show()
        Me.TopMost = True
        WaitTickCount(500)
        Me.TopMost = False


    End Sub

    ''' <summary>「このプログラムについて」のボタンを押された時の処理</summary>
    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Log.Add("----------------------------------------------------------------" + vbCrLf)
        Log.Add(TITLE + " " + VERSION + vbCrLf)
        Log.Add(OPENING_MSG)
        Log.Add(vbCrLf)
        Log.Add("----------------------------------------------------------------" + vbCrLf)
        Log.Put("")
    End Sub

    ''' <summary>ログの表示クリアを行う</summary>
    Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
        Log.Clear()
    End Sub

    ''' <summary>プログラムの終了ボタンを押された。</summary>
    Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click

        'ここで　closingイベントが発生。
        Me.Close()
        End

    End Sub

    Public Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

    End Sub

    Private Sub TextBox4_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox4.DragEnter

        'ファイル形式の場合のみ、ドラッグを受け付けます。
        If e.Data.GetDataPresent(DataFormats.FileDrop) = True Then
            e.Effect = DragDropEffects.Copy
        Else
            e.Effect = DragDropEffects.None
        End If

    End Sub

    Private Function PngTransLayerCheck(PngFileName As String) As Integer

        'Log.Put("tRNS Chunk Check:" + PngFileName)
        Dim StrArray() As String
        StrArray = Split(PngFileName, "\")
        Dim SplitPngFileName As String = StrArray(StrArray.Length - 1)

        Dim fileSize As Integer ' ファイルのサイズ
        Dim bufPos As Integer = 0 ' データ格納用配列内の追加位置
        Dim buf() As Byte ' データ格納用配列を仮確保

        Using fs As New FileStream(PngFileName, FileMode.Open, FileAccess.Read)

            fileSize = CInt(fs.Length) ' ファイルのサイズ
            ReDim Preserve buf(fileSize - 1)  ' データ格納用配列サイズ決定

            Dim readSize As Integer ' Readメソッドで読み込んだバイト数
            Dim remain As Integer = fileSize ' 読み込むべき残りのバイト数

            While remain > 0
                ' 1024Bytesずつ読み込む
                readSize = fs.Read(buf, bufPos, Math.Min(1024, remain))

                bufPos += readSize
                remain -= readSize
            End While

        End Using
        'Log.Put("filesize:" + fileSize.ToString)

        'buf()の中をチェック
        bufPos = 8 '8byte目から確認
        Dim ChunkSize As UInt32
        Do While (bufPos < filesize)
            ChunkSize = buf(bufPos) * (2 ^ 24) _
                + buf(bufPos + 1) * (2 ^ 16) _
                + buf(bufPos + 2) * (2 ^ 8) _
                + buf(bufPos + 3)
            'Log.Put("chunksize=" + ChunkSize.ToString)
            bufPos = bufPos + 4
            If buf(bufPos) = Asc("t") _
               And buf(bufPos + 1) = Asc("R") _
                And buf(bufPos + 2) = Asc("N") _
                And buf(bufPos + 3) = Asc("S") Then
                Log.Put(SplitPngFileName + " has tRNS chunk.")
                Return 1
            End If
            bufPos = bufPos + 4
            bufPos = bufPos + ChunkSize
            bufPos = bufPos + 4
        Loop

        'Log.Put(SplitPngFileName + " is PNG without tRNS chunk.")

        'Log.Put("Alpha Chunnel Check:" + PngFileName)

        ' PNG(BMP)ファイルオープン
        Using bmp As New Bitmap(PngFileName)
            If bmp.PixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppArgb _
                Or bmp.PixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppPArgb Then
                'アルファチャンネルのあるＰＮＧフォーマット

                Dim bmpdat As BitmapData

                bmpdat = bmp.LockBits(New Rectangle(Point.Empty, bmp.Size), ImageLockMode.ReadOnly, bmp.PixelFormat)
                ReDim Preserve buf(bmp.Width * bmp.Height * 4 - 1)  ' データ格納用配列サイズ決定
                Marshal.Copy(bmpdat.Scan0, buf, 0, buf.Length)
                Dim PixelX As Integer
                Dim PixelY As Integer

                For PixelY = 0 To bmp.Height - 1
                    Application.DoEvents()
                    For PixelX = 0 To bmp.Width - 1
                        Dim Alpha As Byte
                        Dim Red As Byte
                        Dim Green As Byte
                        Dim Blue As Byte
                        'αチャンネル 0:透明 ～ 255:完全不透明
                        Alpha = buf((PixelY * bmp.Width + PixelX) * 4 + 3)
                        Red = buf((PixelY * bmp.Width + PixelX) * 4 + 2)
                        Green = buf((PixelY * bmp.Width + PixelX) * 4 + 1)
                        Blue = buf((PixelY * bmp.Width + PixelX) * 4 + 0)
                        If Alpha < 255 Then
                            Log.Put(SplitPngFileName + " has alpha chunnel.")
                            Log.Put("(X,Y) ARGB = " + PixelX.ToString + "," + PixelY.ToString + "," + Alpha.ToString + "," + Red.ToString + "," + Green.ToString + "," + Blue.ToString)
                            Return 1
                        End If
                    Next
                Next
            End If
        End Using

        Return 0

    End Function

    Private Sub TextBox4_DragDrop(sender As Object, e As DragEventArgs) Handles TextBox4.DragDrop

        TextBox4.Enabled = False

        'ドラッグされたファイル・フォルダのパスを格納します。
        Dim strFileName As String() = CType(e.Data.GetData(DataFormats.FileDrop, False), String())
        Dim TextBox4BackColor = TextBox4.BackColor
        TextBox4.BackColor = frmMain.BackColor

        For Each OrgFileName As String In strFileName

            Application.DoEvents()

            ' 読み込んだ結果をすべて格納するための変数を宣言する
            Dim Result As String
            Dim StrArray() As String
            Dim JPGcount As Integer = 0

            Dim ZipFileName As String = Path.GetDirectoryName(OrgFileName) + "\~OfficeJPGconvTemp.zip"
            Dim ExtractPath As String = Path.GetDirectoryName(OrgFileName) + "\~OfficeJPGconvExtract"
            Dim CurrentTypesFileName As String = ExtractPath + "\[Content_Types].xml"
            Dim FileExtension As String = OrgFileName.Substring(OrgFileName.Length - 4).ToLower

            'ファイルの存在確認を行い、ある場合にのみ、
            'テキストボックスにパスを表示します。
            '（この処理でフォルダを対象外にしています。）
            If System.IO.File.Exists(OrgFileName) = True Then
                Log.Put("=====")
                Log.Put(OrgFileName)
            Else
                GoTo NEXT_LOOP
            End If

            If OrgFileName.Substring(OrgFileName.Length - 5).ToLower <> ".xlsx" And
            OrgFileName.Substring(OrgFileName.Length - 5).ToLower <> ".xlsm" And
            OrgFileName.Substring(OrgFileName.Length - 5).ToLower <> ".pptx" And
            OrgFileName.Substring(OrgFileName.Length - 5).ToLower <> ".pptm" And
            OrgFileName.Substring(OrgFileName.Length - 5).ToLower <> ".docx" And
            OrgFileName.Substring(OrgFileName.Length - 5).ToLower <> ".docm" Then
                Log.Put("office2007 ファイル以外には対応していません。")
                GoTo NEXT_LOOP
            End If

            Log.Put("解析中です。")
            Application.DoEvents()

            Try

                File.Delete(ZipFileName)
                File.Copy(OrgFileName, ZipFileName)

                '解凍先フォルダ (ディレクトリ) が存在しているかどうか確認して削除
                '存在の有無を確認しないとExceptionが発生する
                If Directory.Exists(ExtractPath) Then
                    Log.DebugPut("作業用フォルダが存在します。削除します。")
                    Directory.Delete(ExtractPath, True)
                Else
                    Log.DebugPut("作業用フォルダが存在しません。")
                End If

                Try
                    Directory.CreateDirectory(ExtractPath)
                Catch
                    Log.Put("作業用フォルダの作成に失敗しました。")
                    GoTo NEXT_LOOP
                End Try

                Application.DoEvents()

                'ZIP書庫を展開する
                Compression.ZipFile.ExtractToDirectory(
                ZipFileName, ExtractPath,
                System.Text.Encoding.GetEncoding("shift_jis"))

                Application.DoEvents()

                '解凍したZIPの中に [Content_Types].xml があるかどうか確認する。
                If File.Exists(CurrentTypesFileName) Then
                    '存在するのなら正常。次の処理へ
                Else
                    '存在しないなら異常。作業中断
                    Try
                        File.Delete(ZipFileName)
                        Directory.Delete(ExtractPath, True)
                    Catch
                    End Try
                    Log.Put("対象ファイルの解析ができません。")
                    Log.Put("作業を終了します。")
                    GoTo NEXT_LOOP
                End If

                'MediaPath = <ExtractPath>\xl\media
                'MediaPath = <ExtractPath>\ppt\media
                'PNGファイルのリストアップ
                Dim MediaPath As String
                Dim MediaFileNames() As String
                If System.IO.Directory.Exists(ExtractPath + "\xl\media\") Then
                    MediaPath = ExtractPath + "\xl\media"
                    MediaFileNames = Directory.GetFiles(MediaPath, "*.png")
                ElseIf System.IO.Directory.Exists(ExtractPath + "\ppt\media\") Then
                    MediaPath = ExtractPath + "\ppt\media"
                    MediaFileNames = Directory.GetFiles(MediaPath, "*.png")
                ElseIf System.IO.Directory.Exists(ExtractPath + "\word\media\") Then
                    MediaPath = ExtractPath + "\word\media"
                    MediaFileNames = Directory.GetFiles(MediaPath, "*.png")
                Else
                    Try
                        File.Delete(ZipFileName)
                        Directory.Delete(ExtractPath, True)
                    Catch

                    End Try
                    Log.Put("対象ファイルの中にPNG/BMPファイルがありません。")
                    Log.Put("作業を終了します。")
                    GoTo NEXT_LOOP
                End If
#If 0 Then
            For Each MediaFileName As String In MediaFileNames
                Log.Put(MediaFileName)
            Next
#End If
                'relsファイルのリストアップ
                Dim RelsFileNames() As String = System.IO.Directory.GetFiles(ExtractPath, "*.rels", System.IO.SearchOption.AllDirectories)
#If 0 Then
            For Each RelsFileName As String In RelsFileNames
                Log.Put(RelsFileName)
            Next
#End If

                '取得したメディアファイルの処理をする
                For Each MediaFileName As String In MediaFileNames

                    StrArray = Split(MediaFileName, "\")
                    Dim SplitMediaFileName As String = StrArray(StrArray.Length - 1)

                    Log.Put("---")
                    Log.Put(SplitMediaFileName)

                    'ファイルのサイズを取得し小さいサイズのものはスキップ
                    Dim Medialen As Long = New FileInfo(MediaFileName).Length
                    If Medialen < 1024 Then
                        Log.Put("This PNG is too small.")
                        Continue For
                    End If

                    '取得したファイル名を表示する
                    Log.DebugPut(MediaFileName)
                    Log.DebugPut(Medialen.ToString)

                    Dim TmpJpgFileName As String = MediaPath + "~OfficeJPGConvtemp.jpg"

                    'PNGファイルを開く
                    Try
                        '前回の作業ファイルが残っていれば削除する
                        File.Delete(TmpJpgFileName)

                        'PNGに透明色がある場合はJPG化せず、次のPNGファイルを処理する
                        If (1 = PngTransLayerCheck(MediaFileName)) Then
                            Continue For
                        End If

                        'PNG(BMP)ファイルオープン
                        Using bmp As New Bitmap(MediaFileName)

                            'JPEG形式で保存する()
                            bmp.Save(TmpJpgFileName, System.Drawing.Imaging.ImageFormat.Jpeg)

                            'Bitmapファイルをクローズ
                            bmp.Dispose()
                        End Using
                    Catch
                        '不正なBMP/PNGであれば例外が発生する。
                        File.Delete(TmpJpgFileName)
                        '次のPNGファイルの処理へ
                        Continue For
                    End Try

                    Dim Jpglen As Long
                    Jpglen = New FileInfo(TmpJpgFileName).Length
                    If Jpglen <= (Medialen * 0.8) Then
                        File.Delete(MediaFileName)
                        Dim NewMediaFileName As String = ""
                        For j = 0 To 9999
                            If j = 0 Then
                                NewMediaFileName = MediaFileName.Substring(0, MediaFileName.Length - 4) + ".jpeg"
                            Else
                                NewMediaFileName = MediaFileName.Substring(0, MediaFileName.Length - 4) + "(" + (j - 1).ToString + ").jpeg"
                            End If

                            Try
                                File.Move(TmpJpgFileName, NewMediaFileName)
                                Exit For
                            Catch
                            End Try
                        Next j

                        StrArray = Split(NewMediaFileName, "\")
                        Dim SplitNewMediaFileName As String = StrArray(StrArray.Length - 1)

                        Log.Put(SplitMediaFileName + " was converted to " + SplitNewMediaFileName)

                        JPGcount = JPGcount + 1 'ＪＰＧに変換したファイルの数をカウント

                        Application.DoEvents() 'ログ表示更新の為

                        '取得したリレーションファイルの処理をする
                        For Each RelsFileName As String In RelsFileNames
                            'Shift-JISファイルを開く
                            Result = String.Empty
                            Using Reader As New System.IO.StreamReader(RelsFileName, System.Text.Encoding.GetEncoding("shift-jis"))
                                Result = Reader.ReadToEnd
                                'Log.Put(Result)
                            End Using

                            If InStr(Result, SplitMediaFileName) Then
                                'Log.Put(Result)
                                Result = Replace(Result, SplitMediaFileName, SplitNewMediaFileName)
                                '上書モードでShift-JISファイルを開く
                                Using Writer As New System.IO.StreamWriter(RelsFileName, False, System.Text.Encoding.GetEncoding("shift-jis"))
                                    Writer.Write(Result)
                                    'Log.Put(Result)
                                End Using

                            End If
                        Next

                        File.Delete(TmpJpgFileName)

                    Else
                        'JPGファイルにしてもサイズがちいさくならなかった。
                        Log.Put("JPG化してもサイズが小さくなりませんでした。")
                        File.Delete(TmpJpgFileName)
                    End If

                Next

                If JPGcount = 0 Then
                    Log.Put("JPG化すべきデータはありませんでした。")
                    GoTo NEXT_LOOP
                End If

                ' ExtractPath + "\[Content_Types].xml の中を修正する
                Result = String.Empty
                Using Reader As New System.IO.StreamReader(CurrentTypesFileName, System.Text.Encoding.GetEncoding("shift-jis"))
                    Result = Reader.ReadToEnd
                End Using

                '追加 <Default Extension="jpeg" ContentType="application/jpeg"/>
                If InStr(Result.ToLower, "default extension=""jpeg""") Then
                    '変更不要
                Else
                    Result = Replace(Result,
                                 "<Default Extension=""xml"" ContentType=""application/xml""/>",
                                 "<Default Extension=""xml"" ContentType=""application/xml""/><Default Extension=""jpeg"" ContentType=""application/jpeg""/>")
                    '上書モードでShift-JISファイルを開く
                    Using Writer As New System.IO.StreamWriter(CurrentTypesFileName, False, System.Text.Encoding.GetEncoding("shift-jis"))
                        Writer.Write(Result)
                        'Log.Put(Result)
                    End Using
                End If

                'ZIP書庫を作成する
                File.Delete(ZipFileName)
                Compression.ZipFile.CreateFromDirectory(
                ExtractPath, ZipFileName,
                Compression.CompressionLevel.Optimal,
                False,
                System.Text.Encoding.GetEncoding("shift_jis"))

                'オリジナルファイルをリネームする
                For i = 0 To 1000
                    Dim NewOrgFileName As String _
                    = OrgFileName.Substring(0, OrgFileName.Length - 5) + "(" + i.ToString + ")" + OrgFileName.Substring(OrgFileName.Length - 5)
                    Try
                        File.Move(OrgFileName, NewOrgFileName)
                    Catch
                        Continue For
                    End Try
                    Exit For
                Next

                File.Move(ZipFileName, OrgFileName)

                Log.Put("作業終了しました。")

            Catch
                Log.Put("対象ファイルの解析作業ができませんでした。")
                Log.Put("作業を強制終了します。")
            End Try

NEXT_LOOP:
            '作業ファイルとフォルダを削除
            Try
                File.Delete(ZipFileName)
            Catch
            End Try
            Try
                Directory.Delete(ExtractPath, True)
            Catch
            End Try

            WaitTickCount(100)

        Next

        TextBox4.Enabled = True
        TextBox4.BackColor = TextBox4BackColor

    End Sub
End Class
