anchor.diff:          zigZagOrder |> Array.map (fun i -> 
               block.[i]
           )
  +    
  +    let printBits (v : byte) =
  +        let mutable str = ""
  +        let mutable mask = 1uy <<< 7
  +        for _ in 1 .. 8 do
  +            if v &&& mask <> 0uy then str <- str + "1"
  +            else str <- str + "0"
  +            mask <- mask >>> 1
  +        str
  +
  +    member x.Transform(data : PixImage<'a>, quality : Quantization) =
  +        //assert(data.Size.X % 8 = 0 && data.Size.Y % 8 = 0)
  +        let alignedSize = Align.next2 8 data.Size
  +
  +        let blockCount = alignedSize / V2i(8,8)
  +        let blocks = Array.zeroCreate (blockCount.X * blockCount.Y)
  +            
  +        let mat = data.GetMatrix<C4f>()
  +
  +        let mutable i = 0
  +        for y in 0 .. blockCount.Y - 1 do
  +            for x in 0 .. blockCount.X - 1 do
  +                let blockMat = mat.SubMatrix(8 * V2i(x,y), V2i(8,8))
  +
  +                let arr = Array.zeroCreate 64
  +                blockMat.ForeachXYIndex (fun (x : int64) (y : int64) (i : int64) ->
  +                    let v = mat.[i]
  +                    arr.[int x + 8 * int y] <- v.ToV3f()
  +                )
  +                blocks.[i] <- arr
  +                i <- i + 1
  +
  +        blocks |> Array.collect (ycbcrBlock >> dctBlock >> quantifyBlock quality >> zigZagBlock >> Array.map Vec.xyz) 
  +
  +    member x.Encode(data : V3f[]) =
  +        let stream = JpegStream()
  +        stream.WriteBlocks data
  +        printfn "%s" (stream.ToString())
  +        let arr = stream.ToArray()
  +        printfn ""
  +        let mutable str = ""
  +        for i in 0 .. arr.Length - 1 do
  +            let v = arr.[i]
  +            str <- str + printBits v + " "
  +        printfn "%s" str
  +        arr
  +
  +
  +    member x.Compress(data : PixImage<'a>, quality : Quantization) =
  +        let dctBuffer = x.Transform(data, quality)
  +        x.Encode(dctBuffer)
  +    
  +    member x.ToImageData(realSize : V2i, quality : Quantization, scanData : byte[]) =
  +        use ms = new System.IO.MemoryStream()
  +
  +        
  +        let header = [| 0xFFuy; 0xD8uy;  |]
  +        ms.Write(header, 0, header.Length)
  +
  +        let encode (v : uint16) =
  +            [| byte (v >>> 8); byte v |]
  +
  +
  +        let quant = 
  +            Array.concat [
  +                [| 0xFFuy; 0xDBuy; 0x00uy; 0x84uy |]
  +                [| 0x00uy |]
  +                quality.luminance |> zigZagBlock |> Array.map byte
  +                [| 0x01uy |]
  +                quality.chroma |> zigZagBlock |> Array.map byte
  +            ]
  +        ms.Write(quant, 0, quant.Length)
  +
  +        let sof =
  +            Array.concat [
  +                [| 0xFFuy; 0xC0uy; 0x00uy; 0x11uy |]
  +                [| 0x08uy |]
  +                encode (uint16 realSize.Y)
  +                encode (uint16 realSize.X)
  +                [| 0x03uy; |]
  +                [| 0x01uy; 0x11uy; 0x00uy |]
  +                [| 0x02uy; 0x11uy; 0x01uy |]
  +                [| 0x03uy; 0x11uy; 0x01uy |]
  +            ]
  +        ms.Write(sof, 0, sof.Length)
  +
  +        let huff =
  +            let huffSize (spec : HuffmanTable)  =
  +                uint16 (1 + 16 + spec.values.Length)
  +
  +            let encodeHuff (kind : byte) (spec : HuffmanTable) =
  +                Array.concat [
  +                    [| kind |]
  +                    Array.skip 1 spec.counts |> Array.map byte
  +                    spec.values
  +                ]
  +
  +            Array.concat [
  +                [| 0xFFuy; 0xC4uy |]
  +                encode (2us + huffSize Kernels.encoder.dcLuminance + huffSize  Kernels.encoder.dcChroma + huffSize  Kernels.encoder.acLuminance + huffSize  Kernels.encoder.acChroma)
  +
  +                encodeHuff 0x00uy  Kernels.encoder.dcLuminance
  +                encodeHuff 0x01uy  Kernels.encoder.dcChroma
  +                encodeHuff 0x10uy  Kernels.encoder.acLuminance
  +                encodeHuff 0x11uy  Kernels.encoder.acChroma
  +            ]
  +        ms.Write(huff, 0, huff.Length)
  +
  +        let sos = [| 0xFFuy; 0xDAuy; 0x00uy; 0x0Cuy; 0x03uy; 0x01uy; 0x00uy; 0x02uy; 0x11uy; 0x03uy; 0x11uy; 0x00uy; 0x3Fuy; 0x00uy |]
  +        ms.Write(sos, 0, sos.Length)
  +
  +        ms.Write(scanData, 0, scanData.Length)
  +        ms.Write([| 0xFFuy; 0xD9uy |], 0, 2)
  +        ms.ToArray()
  +
  +type Compressor(runtime : Runtime) =
  +    let device = runtime.Device
  +    let pool = runtime.DescriptorPool
  +
  +    let dct = device |> ComputeShader.ofFunction Kernels.dct
  +    let encode = device |> ComputeShader.ofFunction Kernels.encodeKernel
   
       let transform(data : Image) (alignedSize : V2i) (quality : Quantization) (dctBuffer : Buffer<V4f>) =
           use dctInput = pool |> ComputeShader.newInputBinding dct
  
positive.code:         let device = app.Device
          
          let comp = Compressor(app.Runtime)
          
          let rand = RandomSystem()
  
          let pi = 
              let pi = PixImage<byte>(Col.Format.RGBA, V2i(64,64))
              pi.GetMatrix<C4b>().SetByCoord(fun (c : V2l) ->
                  rand.UniformC3f().ToC4b()
              ) |> ignore
              pi
  
          
          Log.startTimed "CPU"
          let cpu = comp.TransformCPU(pi, Quantization.photoshop80) |> Array.chunkBySize 64
          Log.stop()
  
          Log.startTimed "GPU"
          let gpu = comp.TransformGPU(pi, Quantization.photoshop80) |> Array.chunkBySize 64
          for i in 0 .. gpu.Length - 1 do
              let cpu = cpu.[i]
              let gpu = gpu.[i]
  
negative.code: 
          bs.ToArray()
  
      member x.Compress(data : Image, quality : Quantization) : byte[] =
          let alignedSize = data.Size.XY |> Align.next2 8
          let dctBuffer = device.CreateBuffer<V4f>(int64 alignedSize.X * int64 alignedSize.Y)
  