// ParasitemIA Zipped document format. module ParasitemiaUI.PiaZ open System open System.IO open System.IO.Compression open Emgu.CV open Emgu.CV.Structure open Newtonsoft.Json open Types let extension = ".piaz" let filter = "PIA|*.piaz" // Information associated to a document. type JSONInformation = { patientID : string fileVersion : int } // Information associated to each images. type JSONSourceImage = { num : int name : string RBCRadius : float32 // The RBC Radius found by granulometry. parameters : ParasitemiaCore.Config.Parameters dateLastAnalysis : DateTime rbcs : RBC List healthyRBCBrightness : float32 // 0 to 1. infectedRBCBrightness : float32 // 0 to 1. } type DocumentData = { patientID : string images : SourceImage list } let MAIN_ENTRY_NAME = "info.json" let DEFAULT_IMAGE_EXTENSION = ".tiff" let JSON_EXTENSION = ".json" let CURRENT_FILE_VERSION = 3 /// /// Save a document in a give file path. The file may already exist. /// /// /// /// If the file cannot be written let save (filePath : string) (data : DocumentData) = use file = ZipFile.Open (filePath, ZipArchiveMode.Update) // We only delete JSON files and removed images. for e in List.ofSeq file.Entries do // 'ofSeq' to not iterate a collection currently modified. if Path.GetExtension e.Name = JSON_EXTENSION || data.images |> List.exists (fun img -> img.OriginalName = e.Name) |> not then e.Delete () // Main JSON file. let mainEntry = file.CreateEntry (MAIN_ENTRY_NAME, CompressionLevel.Fastest) use mainEntryWriter = new StreamWriter (mainEntry.Open ()) mainEntryWriter.Write (JsonConvert.SerializeObject ({ patientID = data.patientID; fileVersion = CURRENT_FILE_VERSION })) // Write each images and the associated information as a JSON file. for srcImg in data.images do match srcImg.TempFile with | Some imgTempFile -> let imgEntry = file.CreateEntry (srcImg.OriginalName, CompressionLevel.NoCompression) (File.Open (imgTempFile, FileMode.Open, FileAccess.Read)).CopyTo (imgEntry.Open ()) srcImg.TempFile <- None | None -> () //let imgFilename = (string srcImg.Num) + DEFAULT_IMAGE_EXTENSION //let imgEntry = file.CreateEntry (imgFilename, CompressionLevel.NoCompression) //srcImg.Img.ToBitmap().Save (imgEntry.Open (), System.Drawing.Imaging.ImageFormat.Tiff) let imgJSONEntry = file.CreateEntry (srcImg.OriginalName + JSON_EXTENSION, CompressionLevel.Fastest) use imgJSONFileWriter = new StreamWriter (imgJSONEntry.Open ()) imgJSONFileWriter.Write ( JsonConvert.SerializeObject ( { num = srcImg.Num name = srcImg.Name RBCRadius = srcImg.Config.RBCRadius.Pixel parameters = srcImg.Config.Parameters dateLastAnalysis = srcImg.DateLastAnalysis rbcs = srcImg.RBCs healthyRBCBrightness = srcImg.HealthyRBCBrightness infectedRBCBrightness = srcImg.InfectedRBCBrightness } ) ) let updateDocumentData (fromVersion : int) (toVersion : int) (data : DocumentData) : DocumentData = for v in fromVersion + 1 .. toVersion do match v with | 1 -> // Version 0 -> 1 : set initial brightness for rbc. data.images |> List.iter (fun i -> i.HealthyRBCBrightness <- 1.f; i.InfectedRBCBrightness <- 1.f) | _ -> () data exception VersionFileNewerException of int /// /// Load document from a give file path. /// /// Path to the PiaZ file /// /// If the file cannot be read /// If the file version is newer than the current supported version let load (filePath : string) (defaultConfig : ParasitemiaCore.Config.Config) : DocumentData = use file = ZipFile.Open (filePath, ZipArchiveMode.Read) let mainEntry = file.GetEntry (MAIN_ENTRY_NAME) use mainEntryReader = new StreamReader (mainEntry.Open ()) let info = JsonConvert.DeserializeObject (mainEntryReader.ReadToEnd ()) if info.fileVersion > CURRENT_FILE_VERSION then raise <| VersionFileNewerException info.fileVersion updateDocumentData info.fileVersion CURRENT_FILE_VERSION { patientID = info.patientID images = [ for imgEntry in file.Entries do if imgEntry.Name.EndsWith JSON_EXTENSION |> not then use bitmap = new System.Drawing.Bitmap (imgEntry.Open (), false) let img = bitmap.ToImage () let imgJSONEntry = file.GetEntry (imgEntry.Name + JSON_EXTENSION) use imgJSONFileReader = new StreamReader (imgJSONEntry.Open ()) let imgInfo = JsonConvert.DeserializeObject (imgJSONFileReader.ReadToEnd ()) let imgNum = imgInfo.num let config = defaultConfig.Copy () config.Parameters <- { ParasitemiaCore.Config.defaultParameters with resolution = imgInfo.parameters.resolution } config.SetRBCRadius imgInfo.RBCRadius SourceImage (imgNum, imgInfo.name, imgEntry.Name, config, imgInfo.dateLastAnalysis, FromMemory img, imgInfo.rbcs, HealthyRBCBrightness = imgInfo.healthyRBCBrightness, InfectedRBCBrightness = imgInfo.infectedRBCBrightness) ] |> List.sortBy (fun image -> image.Num) }