午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFとVBで複数画像(BitmapSource)とシリアライズした文字列(String)や数値(Integerとか)を1つのZipファイルにする

 
複数画像(BitmapSource)とシリアライズした文字列(String)や数値(Integerとか)を1つのZipファイルにする
 
 
前々回では複数画像を文字列に変換してシリアライズしていた

gogowaten.hatenablog.com

WPFVB.NET、複数のBitmapSourceを1つにしてシリアライズしてファイルに保存 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14072509.html
けど
今回はTIFFpngどちらかの画像に変換してZipファイルに収めることにした
 
文字列(String)や数値(Integerとか)の部分は前回の
WPFVB.NETでデータをシリアライズしてZipファイルに保存 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14077359.html
これと同じ
 
イメージ 1
今回のを実行したところ
 
イメージ 2
左が元の画像2つ
回転角度の数値はシリアライズしてdata.binとういう名前で保存
二つの画像はそれぞれTIFF形式とPNG形式へ変換したものを保存
画像と回転角度をまとめてZipファイルにして
これを読み込んで再現したのが中央と右側の画像
 
 
Zipファイルはアプリの実行ファイルと同じフォルダに作成

f:id:gogowaten:20191025130637p:plain

savePng.zipとsaveTiff.zipがそれ
中の状態は
 
TIFF形式

f:id:gogowaten:20191025130648p:plain

TIFFは1つのファイルに複数画像を収められるので1つのTIFFファイルと
回転角度を収めたdata.bin
 
PNG形式

f:id:gogowaten:20191025130703p:plain

PNGは保存する画像の枚数分のPNGファイルと回転角度のdata.bin
 
以上が結果
 
デザイン画面とXAML

f:id:gogowaten:20191025130713p:plain

sp1、sp2、sp3と名前をつけたStackPanelを3つ横に並べただけ
 
 
VBコード

f:id:gogowaten:20191025130726p:plain

Imports System.IO
Imports System.IO.Compression


Class MainWindow
    Private bitmapList As New List(Of BitmapSource)
    Private DataList As New List(Of SaveData)
    Private Sub initial()
        Dim fileName1 As String = "D:\ブログ用\テスト用画像\hueRect030.png"
        Dim fileName2 As String = "D:\ブログ用\テスト用画像\hueRect210.png"
        DataList.Add(New SaveData With {.angle = 30, .name = fileName1})
        DataList.Add(New SaveData With {.angle = 12.345, .name = fileName2})
        bitmapList.Add(New BitmapImage(New Uri(fileName1)))
        bitmapList.Add(New BitmapImage(New Uri(fileName2)))

        For i As Integer = 0 To bitmapList.Count - 1
            Dim img As New Image
            With img
                .Source = bitmapList(i)
                .RenderTransform = New RotateTransform(DataList(i).angle)
                .Name = "image" & i
                .Stretch = Stretch.None
            End With
            sp1.Children.Add(img)
        Next

    End Sub
    Private Sub SaveTiff()
        '複数画像を1つのTIFF画像に変換
        Dim encoder As New TiffBitmapEncoder
        Dim frame As BitmapFrame
        For i As Integer = 0 To bitmapList.Count - 1
            frame = BitmapFrame.Create(bitmapList(i))
            encoder.Frames.Add(frame)
        Next
        Dim zipPath As String = My.Application.Info.DirectoryPath & "\" & "saveTiff.zip"

        Using zipStream As Stream = File.Create(zipPath)

            Using archive As New ZipArchive(zipStream, ZipArchiveMode.Create)
                Dim entry As ZipArchiveEntry = archive.CreateEntry("bmp.tiff")
                Using entryStream As Stream = entry.Open
                    Using ms As New MemoryStream
                        encoder.Save(ms)
                        ms.Position = 0
                        ms.CopyTo(entryStream)
                    End Using
                End Using

                Using msAngle As New MemoryStream
                    Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                    bf.Serialize(msAngle, DataList)
                    entry = archive.CreateEntry("data.bin")
                    Using entryStreamAngle As Stream = entry.Open
                        msAngle.Position = 0
                        msAngle.CopyTo(entryStreamAngle)
                    End Using
                End Using

            End Using
        End Using
    End Sub
    Private Sub LoadTiff()

        Dim zipPath As String = My.Application.Info.DirectoryPath & "\" & "saveTiff.zip"
        Dim bitmapListFromZip As New List(Of BitmapSource)
        Dim DataListFromZip As New List(Of SaveData)
        Using zipStream As Stream = File.OpenRead(zipPath)
            Using archive As New ZipArchive(zipStream, ZipArchiveMode.Read)
                Dim entry As ZipArchiveEntry = archive.GetEntry("bmp.tiff")
                Using entryStream = entry.Open
                    Using ms As New MemoryStream
                        entryStream.CopyTo(ms)
                        ms.Position = 0
                        Dim decorder As New TiffBitmapDecoder(ms, BitmapCreateOptions.None, BitmapCacheOption.OnLoad)
                        For i As Integer = 0 To bitmapList.Count - 1
                            bitmapListFromZip.Add(decorder.Frames(i))
                        Next
                    End Using
                End Using

                entry = archive.GetEntry("data.bin")
                Using entryStream As Stream = entry.Open
                    Using ms As New MemoryStream
                        entryStream.CopyTo(ms)
                        ms.Position = 0
                        Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                        DataListFromZip = bf.Deserialize(ms)
                    End Using
                End Using
            End Using
        End Using

        For i As Integer = 0 To bitmapListFromZip.Count - 1
            Dim img As New Image
            With img
                .Source = bitmapListFromZip(i)
                .RenderTransform = New RotateTransform(DataListFromZip(i).angle)
                .Name = "image" & i
                .Stretch = Stretch.None
            End With
            sp2.Children.Add(img)
        Next
    End Sub
    Private Sub SavePng()
        Dim zipPath As String = My.Application.Info.DirectoryPath & "\" & "savePng.zip"
        Using zipStream As Stream = File.Create(zipPath)

            Using archive As New ZipArchive(zipStream, ZipArchiveMode.Create)
                For i As Integer = 0 To bitmapList.Count - 1
                    Dim encoder As New PngBitmapEncoder
                    Dim fileName As String = i & ".png"
                    Dim entry As ZipArchiveEntry = archive.CreateEntry(fileName)
                    Dim frame As BitmapFrame = BitmapFrame.Create(bitmapList(i))
                    encoder.Frames.Add(frame)
                    Using entryStream As Stream = entry.Open
                        Using ms As New MemoryStream
                            encoder.Save(ms)
                            ms.Position = 0
                            ms.CopyTo(entryStream)
                        End Using
                    End Using
                Next

                Using msAngle As New MemoryStream
                    Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                    bf.Serialize(msAngle, DataList)
                    Dim entry As ZipArchiveEntry = archive.CreateEntry("data.bin")
                    Using entryStreamAngle As Stream = entry.Open
                        msAngle.Position = 0
                        msAngle.CopyTo(entryStreamAngle)
                    End Using
                End Using

            End Using
        End Using
    End Sub
    Private Sub LoadPng()
        Dim zipPath As String = My.Application.Info.DirectoryPath & "\" & "savePng.zip"
        Dim bitmapListFromZip As New List(Of BitmapSource)
        Dim DataListFromZip As New List(Of SaveData)
        Using zipStream As Stream = File.OpenRead(zipPath)
            Using archive As New ZipArchive(zipStream, ZipArchiveMode.Read)
                For i As Integer = 0 To bitmapList.Count - 1
                    Dim fileName As String = i & ".png"
                    Dim entryB As ZipArchiveEntry = archive.GetEntry(fileName)
                    Using entryStream = entryB.Open
                        Using ms As New MemoryStream
                            entryStream.CopyTo(ms)
                            ms.Position = 0
                            Dim decorder As New PngBitmapDecoder(ms, BitmapCreateOptions.None, BitmapCacheOption.OnLoad)
                            bitmapListFromZip.Add(decorder.Frames(0))
                        End Using
                    End Using
                Next

                Dim entry As ZipArchiveEntry = archive.GetEntry("data.bin")
                Using entryStream As Stream = entry.Open
                    Using ms As New MemoryStream
                        entryStream.CopyTo(ms)
                        ms.Position = 0
                        Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                        DataListFromZip = bf.Deserialize(ms)
                    End Using
                End Using
            End Using
        End Using
        For i As Integer = 0 To bitmapListFromZip.Count - 1
            Dim img As New Image
            With img
                .Source = bitmapListFromZip(i)
                .RenderTransform = New RotateTransform(DataListFromZip(i).angle)
                .Name = "image" & i
                .Stretch = Stretch.None
            End With
            sp3.Children.Add(img)
        Next
    End Sub
    Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
        Call initial()

        Call SaveTiff()
        Call LoadTiff()

        Call SavePng()
        Call LoadPng()
    End Sub

End Class
<Serializable>
Public Class SaveData
    Public Property angle As Double
    Public Property name As String
End Class
 
 
画像以外の情報を入れておくクラス
イメージ 8
angleに回転角度を入れて
Nameは文字列
 
 
イメージ 10
Zipファイルを扱うのでSystem.IO.Compressionを参照に追加しておく
追加方法は前回の記事
BitmapListに元の画像として表示しているBitmapSourceを全部入れておく
DataListはさっきのsaveDataクラスを全部入れておくリスト
ホントはこのふたつを一つにまとめたい
 
アプリ起動時、Initializedイベント
イメージ 9
アプリ起動時に保存から読込まで全部実行させる
 
準備
イメージ 11
二つの画像ファイルを読み込んでリストに追加
回転角度を適当に決めてSaveDataクラスを作ってリストに追加
Imageコントロールを作っていろいろ設定
表示する画像の指定や回転角度はさっきのリストを使って設定
作成したImageはsp1に追加して表示
 
 
TIFF形式の画像とシリアライズしたSaveDataをZipファイルにする
イメージ 12
必要ないのが真ん中辺りにある2行
Dim b as Byte()~
Dim ta as Byte()~
これ要らない
それ以外は前回とほとんど同じかなあ
違うのはZipに入れるのが画像とSaveDataの2つに増えたから
ZipArchiveEntryも2つになったこと
 
 
保存したZipファイルを読み込んで画像表示
イメージ 13
読込の部分も前回とほとんど同じ
複数画像を収めたTIFF画像からの画像取り出しは普通にTiffBitmapDecoderに
読みこめば、そのFramesの中にBitmapSourceが順番に入っているのでそれを取り出すだけ
 
 
PNG形式でZipの場合
イメージ 14
Tiffと違うのは元の画像枚数分のPNG画像を作成して、連番の名前を付けてZipに入れていること
PNGでもFrames.Add(BitmapFrame)でどんどん画像追加できて
保存もできたんだけど、これを読み込んでも取り出せなかったので
枚数分作成している
 
PNGで保存したZipから読込して画像表示
イメージ 15
Tiffと違うのは画像取り出しの時に名前を指定して取り出しているところ
Dim fileName As String = i & ".png"
Dim entryB As ZipArchiveEntry = archive.GetEntry(fileName)
Tiffは連番のIndexで指定しているからこの部分の処理はTiffのほうが早そう
 
 
PNGTIFF ファイルサイズ
PNGTIFF 処理時間、手間
一長一短でどちらにしようか迷うけどTIFFにしようかなあ
 
ファイルサイズ(KB)
   5.22 今回のPNGに変換してZip
   6.78 今回のTIFFに変換してZip
122 前回の文字列に変換してZip
こうしてみるとPNGTIFFのサイズの違いは文字列に変換と比べると誤差程度
写真画像ならまた違ってくるんだろうけど、文字列に変換はどうしてもシリアライズしたい時しか出番はなさそう
 
 
目的のPixtack紫陽花2ndの編集状態を保存しておいて、次回の起動時に編集状態を再現したいってのは今回のでできるはず、なんだけどあっちは回転角度とかはスライダーとも連携しているから、なんか複雑なことになりそう、DataBindingとか使えればスッキリできできそうかなってのもある、うーん
 
 
今回のコード
 
 
 
関連記事