// 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)
}