To .NET 5 (lot of refactoring)
[master-thesis.git] / Parasitemia / ParasitemiaUI / PiaZ.fs
1 // ParasitemIA Zipped document format.
2 module ParasitemiaUI.PiaZ
3
4 open System
5 open System.IO
6 open System.IO.Compression
7
8 open Emgu.CV
9 open Emgu.CV.Structure
10
11 open Newtonsoft.Json
12
13 open Types
14
15 let extension = ".piaz"
16 let filter = "PIA|*.piaz"
17
18 // Information associated to a document.
19 type JSONInformation =
20 {
21 patientID : string
22 fileVersion : int
23 }
24
25 // Information associated to each images.
26 type JSONSourceImage =
27 {
28 num : int
29 name : string
30
31 RBCRadius : float32 // The RBC Radius found by granulometry.
32 parameters : ParasitemiaCore.Config.Parameters
33 dateLastAnalysis : DateTime
34 rbcs : RBC List
35
36 healthyRBCBrightness : float32 // 0 to 1.
37 infectedRBCBrightness : float32 // 0 to 1.
38 }
39
40 type DocumentData =
41 {
42 patientID : string
43 images : SourceImage list
44 }
45
46 let mainEntryName = "info.json"
47 let imageExtension = ".tiff"
48 let currentFileVersion = 2
49
50 /// <summary>
51 /// Save a document in a give file path. The file may already exist.
52 /// </summary>
53 /// <param name="filePath"></param>
54 /// <param name="data"></param>
55 /// <exception cref="System.IOException">If the file cannot be written</exception>
56 let save (filePath : string) (data : DocumentData) =
57 use file = ZipFile.Open (filePath, ZipArchiveMode.Update)
58
59 for e in List.ofSeq file.Entries do // 'ofSeq' to not iterate a collection currently modified.
60 e.Delete ()
61
62 // Main JSON file.
63 let mainEntry = file.CreateEntry (mainEntryName, CompressionLevel.Fastest)
64 use mainEntryWriter = new StreamWriter (mainEntry.Open ())
65 mainEntryWriter.Write (JsonConvert.SerializeObject ({ patientID = data.patientID; fileVersion = currentFileVersion }))
66
67 // Write each images and the associated information.
68 for srcImg in data.images do
69 let imgFilename = (string srcImg.Num) + imageExtension
70 let imgEntry = file.CreateEntry (imgFilename, CompressionLevel.NoCompression) // FIXME: It seems a compression is applied to this file despite of the 'NoCompression' flag.
71 srcImg.Img.ToBitmap().Save (imgEntry.Open (), System.Drawing.Imaging.ImageFormat.Tiff)
72
73 let imgJSONEntry = file.CreateEntry (imgFilename + ".json", CompressionLevel.Fastest)
74 use imgJSONFileWriter = new StreamWriter (imgJSONEntry.Open ())
75 imgJSONFileWriter.Write (
76 JsonConvert.SerializeObject (
77 {
78 num = srcImg.Num
79 name = srcImg.Name
80 RBCRadius = srcImg.Config.RBCRadius.Pixel
81 parameters = srcImg.Config.Parameters
82 dateLastAnalysis = srcImg.DateLastAnalysis
83 rbcs = srcImg.RBCs
84 healthyRBCBrightness = srcImg.HealthyRBCBrightness
85 infectedRBCBrightness = srcImg.InfectedRBCBrightness
86 }
87 )
88 )
89
90 let updateDocumentData (fromVersion : int) (toVersion : int) (data : DocumentData) : DocumentData =
91 for v in fromVersion + 1 .. toVersion do
92 match v with
93 | 1 -> // Version 0 -> 1 : set initial brightness for rbc.
94 data.images |> List.iter (fun i -> i.HealthyRBCBrightness <- 1.f; i.InfectedRBCBrightness <- 1.f)
95 | _ -> ()
96 data
97
98 /// <summary>
99 /// Load document from a give file path.
100 /// </summary>
101 /// <param name="filePath">Path to the PiaZ file</param>
102 /// <param name="defaultConfig"></param>
103 /// <exception cref="System.IOException">If the file cannot be read</exception>
104 let load (filePath : string) (defaultConfig : ParasitemiaCore.Config.Config) : DocumentData =
105 use file = ZipFile.Open (filePath, ZipArchiveMode.Read)
106
107 let mainEntry = file.GetEntry (mainEntryName)
108 use mainEntryReader = new StreamReader (mainEntry.Open ())
109 let info = JsonConvert.DeserializeObject<JSONInformation> (mainEntryReader.ReadToEnd ())
110
111 updateDocumentData info.fileVersion currentFileVersion
112 {
113 patientID = info.patientID
114 images =
115 [
116 let mutable imgNum = 0
117 for imgEntry in file.Entries do
118 if imgEntry.Name.EndsWith (imageExtension) then
119 use bitmap = new System.Drawing.Bitmap (imgEntry.Open (), false)
120 let img = bitmap.ToImage<Bgr, byte> ()
121 imgNum <- imgNum + 1
122 let imgJSONEntry = file.GetEntry (imgEntry.Name + ".json")
123 use imgJSONFileReader = new StreamReader (imgJSONEntry.Open ())
124 let imgInfo = JsonConvert.DeserializeObject<JSONSourceImage> (imgJSONFileReader.ReadToEnd ())
125
126 let config = defaultConfig.Copy ()
127 config.Parameters <-
128 {
129 ParasitemiaCore.Config.defaultParameters with
130 resolution = imgInfo.parameters.resolution
131 }
132
133 config.SetRBCRadius imgInfo.RBCRadius
134
135 SourceImage (imgNum, imgInfo.name, config, imgInfo.dateLastAnalysis, img, imgInfo.rbcs, HealthyRBCBrightness = imgInfo.healthyRBCBrightness, InfectedRBCBrightness = imgInfo.infectedRBCBrightness)
136 ]
137 }