anchor.diff:                  x.Write huff
                   x.Write(Codeword.Create(dc, v))
   
  -        let writeBlock (bs : BitStream) (block : V3i[]) =
  -
  -            bs.WriteDCLum(block.[0].X)
  +        let writeBlock (bs : BitStream) (lastDC : V3i) (block : V3i[]) =
  +
  +            bs.WriteDCLum(block.[0].X - lastDC.X)
               let mutable leading = 0
               let mutable i = 1 
               while i < 64 do
  
positive.code:                 
                  0.25 * cx * cy * sum
              )
  
          let printMat8 (arr : 'a[]) =
              arr |> Array.map (sprintf "%A") |> Array.chunkBySize 8 |> Array.map (String.concat " ") |> String.concat "\r\n"
  
  
  
          let testBlock =
              [|
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
                  V3d.IOO; V3d.IOO; V3d.IOO; V3d.IOO; V3d.OIO; V3d.OIO; V3d.OIO; V3d.OIO
              |]
  //            [|
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //                V3d.III; V3d.III; V3d.III; V3d.III; V3d.OOO; V3d.OOO; V3d.OOO; V3d.OOO
  //            |]
  
          [<StructuredFormatDisplay("{AsString}")>]
          type Codeword =
              struct
                  val mutable public Store : uint16
                  val mutable public LengthStore : uint8
  
  
                  member inline x.Length = int x.LengthStore
  
  
                  member private x.AsString = x.ToString()
                  override x.ToString() =
                      if x.LengthStore = 0uy then
                          "(0)"
                      else
                          let mutable res = sprintf "(%d:" x.LengthStore
                          let mutable mask = 1us <<< 15
                          for i in 1 .. int x.Length do
                              if x.Store &&& mask <> 0us then res <- res + "1"
                              else res <- res + "0"
                              mask <- mask >>> 1
                          res + ")"
  
                  member x.FullString =
                      let mutable res = sprintf "(%d:" x.LengthStore
                      let mutable mask = 1us <<< 15
                      for i in 1 .. 16 do
                          if x.Store &&& mask <> 0us then res <- res + "1"
                          else res <- res + "0"
                          mask <- mask >>> 1
                      res + ")"
                      
                  member x.ToByteArray() =
                      if x.Length = 0 then [||]
                      elif x.Length <= 8 then [| byte (x.Store >>> 8) |]
                      else [| byte (x.Store >>> 8); byte x.Store |]
  
                  member x.Take(count : int) =
                      if count > x.Length || count < 0 then failwith "[Codeword] cannot skip"
  
                      let mask = ((1us <<< count) - 1us) <<< (16 - count)
  
                      Codeword(count, x.Store &&& mask)
  
                  member x.Skip(count : int) =
                      if count > x.Length || count < 0 then failwith "[Codeword] cannot take"
  
                      let rem = x.Length - count
                      //let mask = (1us <<< rem) - 1us
                      Codeword(rem, x.Store <<< count)
  
                  member x.Append(other : Codeword) =
                      let len = x.Length + other.Length
                      if len > 16 then failwith "[Codeword] cannot append"
  
                      let other = other.Store >>> x.Length
                      Codeword(len, x.Store ||| other)
  
  
                  member x.AppendBit (b : bool) =
                      if x.Length >= 16 then failwith "[Codeword] cannot append to full codeword"
  
                      if b then 
                          let n = 1us <<< (15 - x.Length)
                          Codeword(x.Length + 1, x.Store ||| n)
                      else 
                          Codeword(x.Length + 1, x.Store)
  
                  static member Create (length : int, code : uint16) =
                      // mask the higher bits
                      let code = code &&& ((1us <<< length) - 1us)
  
                      // shift the code to the beginning
                      let code = code <<< (16 - length)
  
                      Codeword(length, code)
                  static member Empty = Codeword(0, 0us)
  
                  private new(length : int, code : uint16) = { Store = code; LengthStore = byte length}
  
              end
  
          let QLum =
              [|
                  2;  2;  2;  2;  3;  4;  5;  6;
                  2;  2;  2;  2;  3;  4;  5;  6;
                  2;  2;  2;  2;  4;  5;  7;  9;
                  2;  2;  2;  4;  5;  7;  9; 12;
                  3;  3;  4;  5;  8; 10; 12; 12;
                  4;  4;  5;  7; 10; 12; 12; 12;
                  5;  5;  7;  9; 12; 12; 12; 12;
                  6;  6;  9; 12; 12; 12; 12; 12;
              |]
  
          let QChrom =
              [|
                   3;  3;  5;  9; 13; 15; 15; 15;
                   3;  4;  6; 11; 14; 12; 12; 12;
                   5;  6;  9; 14; 12; 12; 12; 12;
                   9; 11; 14; 12; 12; 12; 12; 12;
                  13; 14; 12; 12; 12; 12; 12; 12;
                  15; 12; 12; 12; 12; 12; 12; 12;
                  15; 12; 12; 12; 12; 12; 12; 12;
                  15; 12; 12; 12; 12; 12; 12; 12;
              |]
              
  
          let quantify (block : V3d[]) =
              let round (v : V3d) = V3i(int (round v.X), int (round v.Y), int (round v.Z))
              Array.map3 (fun ql qc v -> round(v / V3d(float ql,float qc,float qc))) QLum QChrom block
  
  
          type TableSpec =
              {
  
negative.code: 
  
          let test() = 
              testBlocks
                  |> List.map (ycbcr >> dct >> quantify >> zigZag)
                  |> writeImage imageSize
  
  
  
      let testscan() =
          let data = Jpeg.test()
          //data |> Array.map (sprintf "0x%02X") |> String.concat ";" |> printfn "%s"
          Log.warn "total size: %d (%.3f bpp)" data.Length (float (8 * data.Length) / float (Jpeg.imageSize.X * Jpeg.imageSize.Y))
  
          File.writeAllBytes @"C:\Users\Schorsch\Desktop\wtf.jpg" data
  
  