//#define USE_DEFAULT_COLORS
#define USE_ACTUAL_COLORS

//C:\Users\nejat\Documents\vid sabri  4 64 80 1
// C:\Users\nejat\Documents\sabrina sabrina 4 60 80 1
// m sabrina
using ColorMine.ColorSpaces;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;

namespace C64VideoConverter
{
    class Program
    {

        static object[] allColorsArray = new object[256];
        static Lab[] c64Colors = new Lab[16];
        static Rgb[] c64ColorsRgb = new Rgb[16];
        static double[] distanceToOrigin = new double[16];

        static bool clip = true;

        /*
        static double GetDistance(Lab c1, Lab c2)
        {
            double distance = ((c1.L - c2.L) * (c1.L - c2.L)) + ((c1.A - c2.A) * (c1.A - c2.A)) + ((c1.B - c2.B) * (c1.B - c2.B));
            distance = Math.Sqrt(distance);
            return distance;
        }
        */

        static double GetDistance(Lab c1, Lab c2)
        {
            //double distance = ((c1.L - c2.L) * (c1.L - c2.L)) + ((c1.A - c2.A) * (c1.A - c2.A))/8 + ((c1.B - c2.B) * (c1.B - c2.B))/8;
            double distance = ((c1.L - c2.L) * (c1.L - c2.L)) + ((c1.A - c2.A) * (c1.A - c2.A)) + ((c1.B - c2.B) * (c1.B - c2.B));
            distance = Math.Sqrt(distance);
            return distance;
        }

        /*
        static double GetDistance(Rgb c1, Rgb c2)
        {
            //double distance = ((c1.L - c2.L) * (c1.L - c2.L)) + ((c1.A - c2.A) * (c1.A - c2.A))/8 + ((c1.B - c2.B) * (c1.B - c2.B))/8;
            double distance = (0.3 * (c1.R - c2.R) ) * (0.3 * (c1.R - c2.R)) + 
                 + (0.59 * (c1.G - c2.G)) * (0.59 * (c1.G - c2.G)) 
                 + (0.11 * (c1.B - c2.B))  * (0.11 * (c1.B - c2.B));
            distance = Math.Sqrt(distance);
            return distance;
        }
        */

        static double GetDistance(Rgb c1, Rgb c2)
        {
            //double distance = ((c1.L - c2.L) * (c1.L - c2.L)) + ((c1.A - c2.A) * (c1.A - c2.A))/8 + ((c1.B - c2.B) * (c1.B - c2.B))/8;
            double distance = (0.3 * (c1.R - c2.R) ) * (0.3 * (c1.R - c2.R)) + 
                 + (0.50 * (c1.G - c2.G)) * (0.50 * (c1.G - c2.G)) 
                 + (0.20 * (c1.B - c2.B))  * (0.20 * (c1.B - c2.B));
            distance = Math.Sqrt(distance);
            return distance;
        }


        static void Main(string[] args)
        {

            //Console.Out.WriteLine("Deserializing C64 colors");

            //string jsonC64 = File.ReadAllText("Color\\C64Colors.lab");
            //c64Colors = new JavaScriptSerializer().Deserialize<Lab[]>(jsonC64);

            Console.Out.WriteLine("C64 colors deserialized");

            for (int i = 0; i < 16; i++)
                c64ColorsRgb[i] = new Rgb();

            c64ColorsRgb[0].R = 0; c64ColorsRgb[0].G = 0; c64ColorsRgb[0].B = 0;
            c64ColorsRgb[1].R = 255; c64ColorsRgb[1].G = 255; c64ColorsRgb[1].B = 255;
            c64ColorsRgb[2].R = 104; c64ColorsRgb[2].G = 55; c64ColorsRgb[2].B = 43;
            c64ColorsRgb[3].R = 112; c64ColorsRgb[3].G = 164; c64ColorsRgb[3].B = 178;
            c64ColorsRgb[4].R = 111; c64ColorsRgb[4].G = 61; c64ColorsRgb[4].B = 134;
            c64ColorsRgb[5].R = 88; c64ColorsRgb[5].G = 141; c64ColorsRgb[5].B = 67;
            c64ColorsRgb[6].R = 53; c64ColorsRgb[6].G = 40; c64ColorsRgb[6].B = 121;
            c64ColorsRgb[7].R = 184; c64ColorsRgb[7].G = 199; c64ColorsRgb[7].B = 111;
            c64ColorsRgb[8].R = 111; c64ColorsRgb[8].G = 79; c64ColorsRgb[8].B = 37;
            c64ColorsRgb[9].R = 67; c64ColorsRgb[9].G = 57; c64ColorsRgb[9].B = 0;
            c64ColorsRgb[10].R = 154; c64ColorsRgb[10].G = 103; c64ColorsRgb[10].B = 89;
            c64ColorsRgb[11].R = 68; c64ColorsRgb[11].G = 68; c64ColorsRgb[11].B = 68;
            c64ColorsRgb[12].R = 108; c64ColorsRgb[12].G = 108; c64ColorsRgb[12].B = 108;
            c64ColorsRgb[13].R = 154; c64ColorsRgb[13].G = 210; c64ColorsRgb[13].B = 132;
            c64ColorsRgb[14].R = 108; c64ColorsRgb[14].G = 94; c64ColorsRgb[14].B = 181;
            c64ColorsRgb[15].R = 149; c64ColorsRgb[15].G = 149; c64ColorsRgb[15 ].B = 149;

            for (int i = 0; i < 16; i++)
            {
                c64Colors[i] = c64ColorsRgb[i].To<Lab>();
            }

            //Console.Out.WriteLine("Deserializing RGB->LAB information");

            //for (int R = 0; R < 256; R++)
            //{
            //    IFormatter formatter = new BinaryFormatter();
            //    Stream stream = new FileStream(String.Format("Color\\MyFile{0}.bin", R), FileMode.Open, FileAccess.Read, FileShare.Read);
            //    Lab[] obj = (Lab[])formatter.Deserialize(stream);
            //    allColorsArray[R] = obj;
            //    stream.Close();

            //    Console.Out.WriteLine(String.Format("{0} finished", R));
            //}

            //Console.Out.WriteLine("RGB->LAB information deserialized");





            string filePath = args[0];

            if (args[0] == "a")
            {
                filePath = args[1];
                Bins2Images(filePath);
            }
            else if (args[0] == "m")
            {
                filePath = args[1];
                Bins2ImagesMulti(filePath);
            }
            else if (args[0] == "d")
            {
                filePath = args[1];
                string outputFilePath = args[2];
                int count = Convert.ToInt32(args[3]);
                ProcessDupImages(filePath, outputFilePath, count);
            } 
            else if (args[0] == "g")
            {
                filePath = args[1];
                GeneratePattern(filePath);
            }
            else if (args[0] == "q")
            {
                filePath = args[1];
                QuantizeToC64Colors(filePath);
            }
            else if (args[0] == "r")
            {
                filePath = args[1];
                string outputFile = args[2];
                int skip = Convert.ToInt32(args[3]);
                int height = Convert.ToInt32(args[4]);
                ProcessImagesRGB(filePath, "Scene", ".png", outputFile, skip, height);
            }
            else
            {
                if (args.Length > 2)
                {
                    string outputFile = args[1];
                    int skip = Convert.ToInt32(args[2]);
                    int yStart = Convert.ToInt32(args[3]);
                    int height = Convert.ToInt32(args[4]);
                    int mc = Convert.ToInt32(args[5]);
                    ProcessImages(filePath, "Scene", ".png", outputFile, skip, yStart, height, mc == 1 ? true : false);
                }
                else if (args.Length > 1)
                {
                    string outputFile = args[1];
                    ProcessImage(filePath, outputFile, 0, 96,false);
                }
                else
                {
                    Bin2Image(filePath);
                }

            }
        }

        static double[] L_errorLine1 = new double[160];
        static double[] L_errorLine2 = new double[160];
        static double[] A_errorLine1 = new double[160];
        static double[] A_errorLine2 = new double[160];
        static double[] B_errorLine1 = new double[160];
        static double[] B_errorLine2 = new double[160];

        private static void InitLines()
        {
            for (int i = 0; i < 160; i++)
            {
                L_errorLine1[i] = 0;
                L_errorLine2[i] = 0;
                A_errorLine1[i] = 0;
                A_errorLine2[i] = 0;
                B_errorLine1[i] = 0;
                B_errorLine2[i] = 0;
            }
        }


        private static void PrepareNextLines()
        {
            for (int i = 0; i < 160; i++)
            {
                L_errorLine1[i] = 0;
                A_errorLine1[i] = 0;
                B_errorLine1[i] = 0;
            }

            double[] temp;
            temp = L_errorLine2;
            L_errorLine2 = L_errorLine1;
            L_errorLine1 = temp;

            temp = L_errorLine2;
            L_errorLine2 = L_errorLine1;
            L_errorLine1 = temp;

            temp = L_errorLine2;
            L_errorLine2 = L_errorLine1;
            L_errorLine1 = temp;
        }


        static double[,] L_errorLine = new double[80,160];
        static double[,] A_errorLine = new double[80,160];
        static double[,] B_errorLine = new double[80,160];


        //private static void InitLine()
        //{
        //    for (int i = 0; i < 160; i++)
        //    {
        //        L_errorLine[i] = 0;
        //        A_errorLine[i] = 0;
        //        B_errorLine[i] = 0;
        //    }
        //}

        private static void ClearErrorImage()
        {
            for (int i = 0;i<80;i++)
            {
                for (int j = 0;j<160;j++)
                {
                    L_errorLine[i, j] = 0;
                    A_errorLine[i, j] = 0;
                    B_errorLine[i, j] = 0;
                }
            }
        }

       
        private static Lab GetNearestC64Color(Lab c1)
        {
            double minDistance = GetDistance(c1, c64Colors[0]);
            byte minDistanceColor = 0;
            for (int j = 1; j < c64Colors.Length; j++)
            {
                double distance = GetDistance(c1, c64Colors[j]);
                if (distance < minDistance)
                {
                    minDistanceColor = (byte)j;
                    minDistance = distance;
                }

            }
            return c64Colors[minDistanceColor];
        }


        private static Rgb GetNearestC64Color(Rgb c1)
        {
            double minDistance = GetDistance(c1, c64ColorsRgb[0]);
            byte minDistanceColor = 0;
            for (int j = 1; j < c64Colors.Length; j++)
            {
                double distance = GetDistance(c1, c64ColorsRgb[j]);
                if (distance < minDistance)
                {
                    minDistanceColor = (byte)j;
                    minDistance = distance;
                }

            }
            return c64ColorsRgb[minDistanceColor];
        }

        private static int GetNearestC64Color(Color color)
        {
            Rgb rgb = new Rgb();
            rgb.R = color.R;
            rgb.G = color.G;
            rgb.B = color.B;

            double minDistance = GetDistance(rgb, c64ColorsRgb[0]);
            byte minDistanceColor = 0;
            for (int j = 1; j < c64Colors.Length; j++)
            {
                double distance = GetDistance(rgb, c64ColorsRgb[j]);
                if (distance < minDistance)
                {
                    minDistanceColor = (byte)j;
                    minDistance = distance;
                }

            }
            return minDistanceColor;
        }

        private static int GetNearestC64Color(Color color, List<int> availableColors)
        {
            Rgb rgb = new Rgb();
            rgb.R = color.R;
            rgb.G = color.G;
            rgb.B = color.B;

            double minDistance = GetDistance(rgb, c64ColorsRgb[availableColors[0]]);
            byte minDistanceColor = (byte) availableColors[0];
            for (int j = 1; j < availableColors.Count; j++)
            {
                double distance = GetDistance(rgb, c64ColorsRgb[availableColors[j]]);
                if (distance < minDistance)
                {
                    minDistanceColor = (byte)availableColors[j];
                    minDistance = distance;
                }

            }
            return minDistanceColor;
        }

        /*
        private static Lab GetNearestC64Color(Lab c1)
        {
            if (c1.L > 50)  return c64Colors[1];
            return c64Colors[0];
        }
        */
        private static double ClipL(double l)
        {
            if (clip)
            {
                if (l > 255) return 255;
                if (l < 0) return 0;
            }


            return l;
        }
        


        private static double ClipC(double c)
        {
            if (clip)
            {
                if (c > 255) return 255;
                if (c < 0) return 0;
            }


            return c;
        }

        private static Bitmap QuantizeToC64Colors(string filePath)
        {
            Console.Out.WriteLine("Processing : " + filePath);
            //FileStream fileStream = File.OpenWrite(outputFile);
            ClearErrorImage();
            Bitmap bitmap = new Bitmap(filePath);
            Bitmap output = new Bitmap(160, 80);
            Bitmap outputActual = new Bitmap(160, 80);
            Bitmap c64Output = new Bitmap(160, 80);

            for (int i = 0;i<80;i++)
            {

                double L_error = 0;
                double A_error = 0;
                double B_error = 0;

                for (int j = 0;j<160;j++)
                {

                    Color color = bitmap.GetPixel(j, i);
                    Rgb rgb = new Rgb();
                    rgb.R = color.R;
                    rgb.G = color.G;
                    rgb.B = color.B;

                    ApplyErrorAndClip(L_errorLine[i, j], A_errorLine[i, j], B_errorLine[i, j], rgb);


                    Rgb nearest = GetNearestC64Color(rgb);

                    L_error = rgb.R - nearest.R;
                    A_error = rgb.G - nearest.G;
                    B_error = rgb.B - nearest.B;

    
                    if (j!=159)
                    {
                        L_errorLine[i, j+1] = ClipL(L_errorLine[i, j + 1] + (L_error * 7) / 16);
                        A_errorLine[i, j+1] = ClipC(A_errorLine[i, j + 1] + (A_error * 7) / 16);
                        B_errorLine[i, j+1] = ClipC(B_errorLine[i, j + 1] + (B_error * 7) / 16);
                    }
                    if (i!=79)
                    {
                        L_errorLine[i + 1,j] = ClipL(L_errorLine[i + 1,j] + (L_error * 5) / 16);
                        A_errorLine[i + 1,j] = ClipC(A_errorLine[i + 1,j] + (A_error * 5) / 16);
                        B_errorLine[i + 1,j] = ClipC(B_errorLine[i + 1,j] + (B_error * 5) / 16);

                        if (j!=0)
                        {
                            L_errorLine[i+1, j-1] = ClipL(L_errorLine[i + 1, j - 1] + (L_error * 3) / 16);
                            A_errorLine[i + 1, j - 1] = ClipC(A_errorLine[i + 1, j - 1] + (A_error * 3) / 16);
                            B_errorLine[i + 1, j - 1] = ClipC(B_errorLine[i + 1, j - 1] + (B_error * 3) / 16);
                        }

                        if (j!=159)
                        {
                            L_errorLine[i + 1, j + 1] = ClipL(L_errorLine[i + 1, j + 1] + (L_error * 1) / 16);
                            A_errorLine[i + 1, j + 1] = ClipC(A_errorLine[i + 1, j + 1] + (A_error * 1) / 16);
                            B_errorLine[i + 1, j + 1] = ClipC(B_errorLine[i + 1, j + 1] + (B_error * 1) / 16);
                        }
                    }





                    output.SetPixel(j, i, Color.FromArgb(Convert.ToInt32(nearest.R), Convert.ToInt32(nearest.G), Convert.ToInt32(nearest.B)));
                    //outputActual.SetPixel(j, i, Color.FromArgb(Convert.ToInt32(rgb.R), Convert.ToInt32(rgb.G), Convert.ToInt32(rgb.B)));
                }
            }

            //output.Save(filePath + ".png");
            //outputActual.Save(filePath + "actual.png");

            List<List<List<int>>> chosenColors = SelectColors(output);


            for (int i = 0; i < 80; i++)
            {
                int row = i / 8;
                for (int j = 0; j < 160; j++)
                {
                    int col = j / 4;

                    Color color = output.GetPixel(j, i);
                    int nearest = GetNearestC64Color(color);

                    List<int> cursorColors = chosenColors[row][col];

                    if (!cursorColors.Exists(x => x == nearest))
                    {
                        nearest = GetNearestC64Color(color, cursorColors);
                    }

                    Rgb rgbColor = c64ColorsRgb[nearest];
                    c64Output.SetPixel(j, i, Color.FromArgb(Convert.ToInt32(rgbColor.R), Convert.ToInt32(rgbColor.G), Convert.ToInt32(rgbColor.B)));               
                }
            }

            //c64Output.Save(filePath + "c64.png");
            return c64Output;
        }

        private static byte GetC64ColorRGB(int red, int green, int blue)
        {
            for (int j = 0; j < c64ColorsRgb.Length; j++)
            {
                if (c64ColorsRgb[j].R == red && c64ColorsRgb[j].G == green && c64ColorsRgb[j].B == blue)
                {
                    return (byte)j;
                }
            }

            return 0;
        }


        private static List<byte> GetColorsRGB(Bitmap bitmap, int startX, int startY)
        {
            List<byte> colors = new List<byte>();
            for (int y = startY; y < startY + 8; y++)
            {
                for (int x = startX; x < startX + 4; x++)
                {
                    if (colors.Count == 3) return colors;
                    Color clr = bitmap.GetPixel(x, y);

                    byte color = GetC64ColorRGB(clr.R, clr.G, clr.B);

                    if (color != 0)
                    {
                        bool found = false;
                        for (int c = 0; c < colors.Count; c++)
                        {
                            if (colors[c] == color)
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found) colors.Add(color);

                    }

                }
            }

            return colors;
        }


        static byte[] ConvertBitmapRGB(Bitmap bitmap, int height)
        {
            List<List<byte>> colorData = new List<List<byte>>();

            for (int row = 0; row < height / 8; row++)
            {
                for (int col = 0; col < 40; col++)
                {
                    List<byte> colors = GetColorsRGB(bitmap, col * 4,  row * 8);
                    colorData.Add(colors);
                }
            }


            byte[] generated = new byte[GetFrameSize(height, true)];
            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
            int[] shiftValue = { 6, 4, 2, 0 };


            for (int y = 0; y < height; y++)
            {
                int row = (y / 8);
                for (int x = 0; x < 160; x++)
                {
                    int column = (x / 4);
                    int color = 0;
                    Color clr = bitmap.GetPixel(x,  y);

                    int colorListIndex = row * 40 + column;
                    List<byte> usedColors = colorData[colorListIndex];

                    for (int i = 0; i < usedColors.Count; i++)
                    {
                        if (GetC64Color(clr.R, clr.G, clr.B) == usedColors[i])
                        {
                            color = i + 1;
                            break;
                        }
                    }

                    int currentByte = row * GetRowSize(true) + (y % 8) + column * 8;
                    int mask = pixelMask[x % 4];
                    int shift = shiftValue[x % 4];
                    generated[currentByte] = Convert.ToByte(generated[currentByte] | Convert.ToByte(mask & (color << shift)));
                }
            }



            for (int row = 0; row < height / 8; row++)
            {
                for (int col = 0; col < 40; col++)
                {
                    int colorListIndex = row * 40 + col;
                    List<byte> colors = colorData[colorListIndex];
                    int currentByteSC = row * GetRowSize(true) + GetBitmapRowSize() + col;

                    byte colorValue = 0;
                    //if (colors.Count > 0) colorValue = (byte)colors[0];
                    //if (colors.Count > 1) colorValue = (byte) (colorValue | (byte)(colors[1] << 4));
                    if (colors.Count > 0) colorValue = (byte)(colors[0] << 4);
                    if (colors.Count > 1) colorValue = (byte)(colorValue | (byte)colors[1]);

                    generated[currentByteSC] = colorValue;

                    int currentByteD800C = row * GetRowSize(true) + GetBitmapRowSize() + 40 + col;

                    if (colors.Count > 2)
                    {
                        generated[currentByteD800C] = colors[2];
                    }
                    else
                    {
                        generated[currentByteD800C] = 0;
                    }

                }
            }

            return generated;
        }


        static byte[] ConvertBitmapRGBDouble(Bitmap bitmap, int height)
        {
            List<List<byte>> colorData = new List<List<byte>>();

            for (int row = 0; row < height / 8; row++)
            {
                for (int col = 0; col < 40; col++)
                {
                    List<byte> colors = GetColorsRGB(bitmap, col * 4, row * 8);
                    colorData.Add(colors);
                }
            }


            byte[] generated = new byte[GetFrameSize(height, true)];
            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
            int[] shiftValue = { 6, 4, 2, 0 };


            for (int y = 0; y < height; y++)
            {
                int row = (y / 8);
                for (int x = 0; x < 160; x++)
                {
                    int column = (x / 4);
                    int color = 0;
                    Color clr = bitmap.GetPixel(x, y);

                    int colorListIndex = row * 40 + column;
                    List<byte> usedColors = colorData[colorListIndex];

                    for (int i = 0; i < usedColors.Count; i++)
                    {
                        if (GetC64Color(clr.R, clr.G, clr.B) == usedColors[i])
                        {
                            color = i + 1;
                            break;
                        }
                    }

                    int currentByte = (y%8<4) ? (row * GetRowSize(true) + (y % 4) + column * 4) : (row * GetRowSize(true) + 160 + (y % 4) + column * 4);
                    int mask = pixelMask[x % 4];
                    int shift = shiftValue[x % 4];
                    generated[currentByte] = Convert.ToByte(generated[currentByte] | Convert.ToByte(mask & (color << shift)));
                }
            }



            for (int row = 0; row < height / 8; row++)
            {
                for (int col = 0; col < 40; col++)
                {
                    int colorListIndex = row * 40 + col;
                    List<byte> colors = colorData[colorListIndex];
                    int currentByteSC = row * GetRowSize(true) + GetBitmapRowSize() + col;

                    byte colorValue = 0;
                    //if (colors.Count > 0) colorValue = (byte)colors[0];
                    //if (colors.Count > 1) colorValue = (byte) (colorValue | (byte)(colors[1] << 4));
                    if (colors.Count > 0) colorValue = (byte)(colors[0] << 4);
                    if (colors.Count > 1) colorValue = (byte)(colorValue | (byte)colors[1]);

                    generated[currentByteSC] = colorValue;

                    int currentByteD800C = row * GetRowSize(true) + GetBitmapRowSize() + 40 + col;

                    if (colors.Count > 2)
                    {
                        generated[currentByteD800C] = colors[2];
                    }
                    else
                    {
                        generated[currentByteD800C] = 0;
                    }

                }
            }

            return generated;
        }


        static void ProcessImagesRGB(string filePath, string filePrefix, string fileSuffix, string outputFile, int skip,  int height)
        {
            FileStream fileStream = File.OpenWrite(outputFile);

            int i = 1;

            while (true)
            {
                string currentFileName = String.Format("{0}{1}{2}", filePrefix, i.ToString().PadLeft(5, '0'), fileSuffix);
                string fullFilePath = String.Format("{0}\\{1}", filePath, currentFileName);
                Console.Out.WriteLine("Processing : " + fullFilePath);
                try
                {
                    Bitmap bitmap = QuantizeToC64Colors(fullFilePath);
                    //byte[] bitmapWithColors = ConvertBitmapRGB(bitmap, height);
                    byte[] bitmapWithColors = ConvertBitmapRGBDouble(bitmap, height);
                    fileStream.Write(bitmapWithColors, 0, bitmapWithColors.Length);
                }
                catch (Exception ex)
                {
                    break;
                }
                i = i + skip;
            }
            fileStream.Close();
        }



        private static List<List<List<int>>> SelectColors(Bitmap image)
        {

            int[,] cMatrix = new int[10, 40];
            List<List<Dictionary<int, int>>> colors = new List<List<Dictionary<int, int>>>();
            List<List<List<int>>> chosenColors = new List<List<List<int>>>();

            List<Dictionary<int, int>> rowColors = new List<Dictionary<int, int>>();
            List<Dictionary<int, int>> colColors = new List<Dictionary<int, int>>();

            for (int i = 0;i<10;i++)
            {
                rowColors.Add(new Dictionary<int, int>());
                colors.Add(new List<Dictionary<int, int>>());
                chosenColors.Add(new List<List<int>>()); 
            }

            for (int i = 0;i<40;i++)
            {
                colColors.Add(new Dictionary<int, int>());
            }


            for (int i = 0;i<10;i++)
            {
                List<Dictionary<int, int>> cellColors = colors[i];
                Dictionary<int, int> rowDictionary = rowColors[i];
                for (int j = 0;j<40;j++)
                {
                    Dictionary<int, int> colDictionary = colColors[j];
                    Dictionary<int, int> x = new Dictionary<int, int>();

                    for (int row=0;row<8;row++)
                    {
                        for (int col=0;col<4;col++)
                        {
                            Color c = image.GetPixel(j * 4 + col, i * 8 + row);
                            int color = GetNearestC64Color(c);
                            if (!x.ContainsKey(color))
                            {
                                x.Add(color, 1);
                            } else
                            {
                                x[color] = x[color] + 1;
                            }

                            if (!rowDictionary.ContainsKey(color))
                            {
                                rowDictionary.Add(color, 1);                                
                            } else
                            {
                                rowDictionary[color] = rowDictionary[color] + 1;
                            }

                            if (!colDictionary.ContainsKey(color))
                            {
                                colDictionary.Add(color, 1);
                            }
                            else
                            {
                                colDictionary[color] = colDictionary[color] + 1;
                            }
                        }
                    }

                    cMatrix[i, j] = x.Count;
                    cellColors.Add(x);
                }
            }


            for (int i = 0; i < 10; i++)
            {
                List<List<int>> chosenColorsRow = chosenColors[i];
                for (int j = 0; j < 40; j++)
                {
                    Dictionary<int, int> usedColors = colors[i][j];
                    List<int> cursorColors = new List<int>();
                    chosenColorsRow.Add(cursorColors);
                    cursorColors.Add(0);

                    var ordered = usedColors.OrderByDescending(x => x.Value);
                    int colorCount = 0;
                    foreach(KeyValuePair<int,int> x in ordered)
                    {
                        if (x.Key!=0)
                        {
                            cursorColors.Add(x.Key);
                            colorCount++;
                        }

                        if (colorCount == 3) break;
                    }
                }
            }


            Console.Out.WriteLine("End");

            return chosenColors;
        }

        private static void ApplyErrorAndClip(double L_forwardError, double A_forwardError, double B_forwardError, Rgb actual)
        {
            actual.R = actual.R + L_forwardError;
            if (clip)
            {
                if (actual.R > 255) actual.R = 255;
                if (actual.R < 0) actual.R = 0;
            }


            actual.G = actual.G + A_forwardError;
            if (clip)
            {
                if (actual.G > 255) actual.G = 255;
                if (actual.G < 0) actual.G = 0;
            }

            actual.B = actual.B + B_forwardError;
            if (clip)
            {
                if (actual.B > 255) actual.B = 255;
                if (actual.B < 0) actual.B = 0;
            }

        }

        private static void GeneratePattern(string filePath)
        {
            FileStream fileStream = File.OpenWrite(filePath);

            ulong f = 0;
            ulong bPrev = 0;
            ulong b = 1;
            int i = 0; 
            while(i<240)
            {
                f = b + bPrev;
                bPrev = b;
                b = f;

                fileStream.WriteByte(Convert.ToByte((f >> 56) & 255));
                fileStream.WriteByte(Convert.ToByte((f >> 48) & 255));
                fileStream.WriteByte(Convert.ToByte((f >> 40) & 255));
                fileStream.WriteByte(Convert.ToByte((f >> 32) & 255));
                fileStream.WriteByte(Convert.ToByte((f >> 24) & 255));
                fileStream.WriteByte(Convert.ToByte((f >> 16) & 255));
                fileStream.WriteByte(Convert.ToByte((f >> 8) & 255));
                fileStream.WriteByte(Convert.ToByte(f&255));
                i = i + 1;                    
            }

            fileStream.Close();
        }

        /*
        static void Bin2Image(string filePath)
        {
            byte[] img = File.ReadAllBytes(filePath);
            int currentByte = 0;
            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
            int[] shiftValue = { 6, 4, 2, 0 };

            Bitmap flag = new Bitmap(160, 96);
            for (int y = 0; y < flag.Height; y++)
            {
                for (int x = 0; x < flag.Width; x++)
                {
                    int mask = pixelMask[x % 4];
                    int shift = shiftValue[x % 4];
                    int color = (img[currentByte] & mask) >> shift;
                    if (color == 0) flag.SetPixel(x, y, Color.Black);
                    if (color == 1) flag.SetPixel(x, y, Color.DarkGray);
                    if (color == 2) flag.SetPixel(x, y, Color.LightGray);
                    if (color == 3) flag.SetPixel(x, y, Color.White);
                    if (x % 4 == 3) currentByte++;
                }                    
            }

            flag.Save(filePath + ".bmp");
        }

        */

        static void Bins2Images(string filePath)
        {
            byte[] imgsAll = File.ReadAllBytes(filePath);
            byte[] colors = new byte[4];
            byte[] img = new byte[3840];
            for (long index = 0; index<imgsAll.Length;index = index + 3840)
            {
                Array.Copy(imgsAll, index, colors, 0, 4);
                Array.Copy(imgsAll, index, img, 0, 3840);
                Bitmap bm = Bin2ImageFB(img, colors);
                bm.Save("out\\scene" + index + ".png");
            }
        }

        static void Bin2Image(string filePath)
        {
            byte[] colors = new byte[4];
            byte[] img = new byte[3840];
            byte[] fc = File.ReadAllBytes(filePath);
            Array.Copy(fc, 0, colors, 0, 4);
            Array.Copy(fc, 0, img, 0, 3840);

            Bitmap flag = Bin2ImageFB(img, colors);
            flag.Save(filePath + ".png");
        }

        static Bitmap Bin2ImageFB(byte[] img, byte[] colors)
        {
            Bitmap flag = new Bitmap(160, 96);
            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
            int[] shiftValue = { 6, 4, 2, 0 };

            for (int y = 0; y < flag.Height; y++)
            {
                int row = (y / 8);
                for (int x = 0; x < flag.Width; x++)
                {
                    int column = (x / 4);
                    int currentByte = row * 320 + (y % 8) + column * 8;
                    int mask = pixelMask[x % 4];
                    int shift = shiftValue[x % 4];
                    int color = (img[currentByte] & mask) >> shift;

                    Lab lab = c64Colors[colors[color]];
                    Rgb rgb = lab.To<Rgb>();

                    flag.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(rgb.R), Convert.ToInt32(rgb.G), Convert.ToInt32(rgb.B)));

                    //if (color == 0) flag.SetPixel(x, y, Color.Black);
                    //if (color == 1) flag.SetPixel(x, y, Color.DarkGray);
                    //if (color == 2) flag.SetPixel(x, y, Color.LightGray);
                    //if (color == 3) flag.SetPixel(x, y, Color.White);
                }
            }

            return flag;
        }


        static void Bins2ImagesMulti(string filePath)
        {
            byte[] imgsAll = File.ReadAllBytes(filePath);
            int frameSize = GetFrameSize(80, true);
            byte[] img = new byte[frameSize];
            for (long index = 0; index < imgsAll.Length; index = index + frameSize)
            {
                Array.Copy(imgsAll, index, img, 0, frameSize);
                Bitmap bm = Bin2ImageFBMulti(img);
                bm.Save("out\\scene" + index + ".png");
            }
        }


        static Bitmap Bin2ImageFBMulti(byte[] img)
        {
            Bitmap flag = new Bitmap(160, 80);
            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
            int[] shiftValue = { 6, 4, 2, 0 };

            for (int y = 0; y < flag.Height; y++)
            {
                int row = (y / 8);
                for (int x = 0; x < flag.Width; x++)
                {
                    int column = (x / 4);
                    int currentByte = row * GetRowSize(true) + (y % 8) + column * 8;
                    int mask = pixelMask[x % 4];
                    int shift = shiftValue[x % 4];
                    int color = (img[currentByte] & mask) >> shift;

                    int currentByteSC = row * GetRowSize(true) + GetBitmapRowSize() + column;
                    int currentByteD800C = row * GetRowSize(true) + GetBitmapRowSize() + 40 + column;

                    int actualScreenColor = img[currentByteSC];
                    int actualD800Color = img[currentByteD800C];

                    int finalColor = 0;
                    if (color == 2)
                    {
                        finalColor = actualScreenColor & 0x0F;
                    } else if (color == 1)
                    {
                        finalColor = (actualScreenColor & 0xF0) >> 4;
                    } else if (color == 3)
                    {
                        finalColor = actualD800Color;
                    }

                    Lab lab = c64Colors[finalColor];
                    Rgb rgb = lab.To<Rgb>();

                    flag.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(rgb.R), Convert.ToInt32(rgb.G), Convert.ToInt32(rgb.B)));
                }
            }

            return flag;
        }


        static void ProcessDupImages(string inputFile, string outputFile, int count)
        {
            //FileStream fileStream = File.OpenWrite(outputFile);
            //Bitmap bitmap = new Bitmap(inputFile);
            //byte[] converted = ConvertBitmapActual(bitmap);

            //for (int i = 0; i < count; i++)
            //{
            //    fileStream.Write(converted, 0, converted.Length);
            //}

            //fileStream.Close();
        }


        static void ProcessImages(string filePath, string filePrefix,string fileSuffix, string outputFile, int skip, int yStart, int height, bool mc)
        {
            FileStream fileStream = File.OpenWrite(outputFile);

            int i = 0;

            while(true)
            {
                string currentFileName = String.Format("{0}{1}{2}", filePrefix, i.ToString().PadLeft(5, '0'), fileSuffix);
                string fullFilePath = String.Format("{0}\\{1}", filePath, currentFileName);
                Console.Out.WriteLine("Processing : " + fullFilePath);
                try
                {
                    Bitmap bitmap = new Bitmap(fullFilePath);
                    Tuple<byte[], byte[]> result = ConvertBitmapActual(bitmap, yStart, height, mc);
                    if (!mc)
                    {
                        byte[] converted = result.Item1;
                        byte[] colors = result.Item2;
                        fileStream.Write(colors, 0, colors.Length);
                        fileStream.Write(colors, 0, colors.Length);
                        fileStream.Write(colors, 0, colors.Length);
                        fileStream.Write(colors, 0, colors.Length);
                        fileStream.Write(converted, 16, converted.Length - 16);
                    } else
                    {
                        byte[] bitmapWithColors = result.Item1;
                        fileStream.Write(bitmapWithColors, 0, bitmapWithColors.Length);
                    }
                } catch(Exception ex)
                {
                    break;
                }
                i = i + skip;
            }
            fileStream.Close();
        }

        static void ProcessImage(string filePath, string outputFile, int yStart, int height, bool mc)
        {

            Console.Out.WriteLine("Processing : " + filePath);
            FileStream fileStream = File.OpenWrite(outputFile);

            Bitmap bitmap = new Bitmap(filePath);

            Tuple<byte[], byte[]> result = ConvertBitmapActual(bitmap, yStart, height, mc);
            if (!mc)
            {
                byte[] converted = result.Item1;
                byte[] colors = result.Item2;
                fileStream.Write(colors, 0, colors.Length);
                fileStream.Write(converted, 4, converted.Length - 4);
                fileStream.Close();
            } else
            {
                byte[] bitmapWithColors = result.Item1;
                fileStream.Write(bitmapWithColors, 0, bitmapWithColors.Length);
            }
        }

        //const int FrameSize = (160 * 100) / 4;
        //const int FrameSize = (320 * 12);
        const int FrameSize = 3840;

        /*
        const float black = 0;
        const float dark_gray = 10/32;
        const float light_gray = 20/32;
        const float white = 32/32;
        */


        const float black = 0;
        const float dark_gray = 8.0f / 32;
        const float light_gray = 16.0f / 32;
        const float white = 24.0f / 32;

        static int GetFrameSize(int height, bool mc)
        {
            int rows = (height / 8);
            int frameSize = rows * GetRowSize(mc);
            return frameSize;
        }

        static int GetRowSize(bool mc)
        {
            if (mc)
            {
                return 320 + 40 + 40;
            } else
            {
                return 320;
            }
        }

        static int GetBitmapRowSize()
        {
            return 320;
        }

        static Tuple<byte[], byte[]> ConvertBitmapActual(Bitmap bitmap, int yStart, int height, bool mc)
        {
            List<List<byte>> colorData = new List<List<byte>>();
            if (mc)
            {

                for (int row = 0; row<height/8; row++)
                {
                    for (int col = 0; col < 40; col++)
                    {
                        List<byte> colors = GetColors(bitmap, col * 4 * 2, yStart + row * 8);
                        colorData.Add(colors);
                    }
                }


                byte[] generated = new byte[GetFrameSize(height, mc)];
                int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
                int[] shiftValue = { 6, 4, 2, 0 };


                for (int y = 0; y < height; y++)
                {
                    int row = (y / 8);
                    for (int x = 0; x < 160; x++)
                    {
                        int column = (x / 4);
                        int color = 0;
                        Color clr = bitmap.GetPixel(x*2, yStart + y);

                        int colorListIndex = row * 40 + column;
                        List<byte> usedColors = colorData[colorListIndex];

                        for (int i = 0; i < usedColors.Count; i++)
                        {
                            if (GetC64Color(clr.R, clr.G, clr.B) == usedColors[i] )
                            {
                                color = i+1;
                                break;
                            }
                        }

                        int currentByte = row * GetRowSize(mc) + (y % 8) + column * 8;
                        int mask = pixelMask[x % 4];
                        int shift = shiftValue[x % 4];
                        generated[currentByte] = Convert.ToByte(generated[currentByte] | Convert.ToByte(mask & (color << shift)));
                    }
                }



                for (int row = 0; row < height / 8; row++)
                {
                    for (int col = 0; col < 40; col++)
                    {
                        int colorListIndex = row * 40 + col;
                        List<byte> colors = colorData[colorListIndex];
                        int currentByteSC = row * GetRowSize(mc) + GetBitmapRowSize() + col;

                        byte colorValue = 0;
                        //if (colors.Count > 0) colorValue = (byte)colors[0];
                        //if (colors.Count > 1) colorValue = (byte) (colorValue | (byte)(colors[1] << 4));
                        if (colors.Count > 0) colorValue =  (byte)(colors[0] << 4);
                        if (colors.Count > 1) colorValue = (byte)(colorValue | (byte)colors[1]);

                        generated[currentByteSC] = colorValue;

                        int currentByteD800C = row * GetRowSize(mc) + GetBitmapRowSize() + 40 + col;

                        if (colors.Count>2)
                        {
                            generated[currentByteD800C] = colors[2];
                        } else
                        {
                            generated[currentByteD800C] = 0;
                        }
                                     
                    }
                }

                return new Tuple<byte[], byte[]>(generated, null);

            }
            else
            {
                List<Rgb> rgbArray = new List<Rgb>();
                int[] count = new int[4];
                byte[] selected = new byte[4];

                //Find colors used in the bitmap
                GetColors(bitmap, rgbArray, count);

                //Colors found. Compare them with C64 colors, find the similar colors.
                for (int i = 0; i < rgbArray.Count; i++)
                {
                    Lab c1 = rgbArray[i].To<Lab>();
                    double minDistance = GetDistance(c1, c64Colors[0]);
                    byte minDistanceColor = 0;
                    for (int j = 1; j < c64Colors.Length; j++)
                    {
                        double distance = GetDistance(c1, c64Colors[j]);
                        if (distance < minDistance)
                        {
                            minDistanceColor = (byte)j;
                            minDistance = distance;
                        }

                    }
                    selected[i] = minDistanceColor;
                }

                byte[] generated = new byte[GetFrameSize(height, mc)];
                int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
                int[] shiftValue = { 6, 4, 2, 0 };


                for (int y = 0; y < height; y++)
                {
                    int row = (y / 8);
                    for (int x = 0; x < 160; x++)
                    {
                        int column = (x / 4);
                        int color = 0;
                        Color clr = bitmap.GetPixel(x, y);


#if USE_ACTUAL_COLORS
                        for (int i = 0; i < rgbArray.Count; i++)
                        {
                            if (rgbArray[i].R == clr.R && rgbArray[i].G == clr.G && rgbArray[i].B == clr.B)
                            {
                                color = i;
                            }
                        }
#endif

#if USE_DEFAULT_COLORS
                    float brightness = clr.GetBrightness();

                    if (brightness < dark_gray)
                    {
                        color = 0;
                    }
                    else if (brightness >= dark_gray && brightness < light_gray)
                    {
                        color = 1;
                    }
                    else if (brightness >= light_gray && brightness < white)
                    {
                        color = 2;
                    }
                    else
                    {
                        color = 3;
                    }
#endif

                        int currentByte = row * GetRowSize(mc) + (y % 8) + column * 8;
                        int mask = pixelMask[x % 4];
                        int shift = shiftValue[x % 4];
                        generated[currentByte] = Convert.ToByte(generated[currentByte] | Convert.ToByte(mask & (color << shift)));
                    }
                }

                return new Tuple<byte[], byte[]>(generated, selected);

            }
        }


        private static byte GetC64Color(int red, int green, int blue)
        {
            Rgb rgb = new Rgb();
            rgb.R = red;
            rgb.G = green;
            rgb.B = blue;
            Lab c1 = rgb.To<Lab>();


            double minDistance = GetDistance(c1, c64Colors[0]);
            byte minDistanceColor = 0;
            for (int j = 1; j < c64Colors.Length; j++)
            {
                double distance = GetDistance(c1, c64Colors[j]);
                if (distance < minDistance)
                {
                    minDistanceColor = (byte)j;
                    minDistance = distance;
                }

            }
            return minDistanceColor;
        }

        private static List<byte> GetColors(Bitmap bitmap, int startX, int startY)
        {
            List<byte> colors = new List<byte>();
            for (int y = startY; y < startY + 8; y++)
            {
                for (int x = startX; x < startX + 8; x = x + 2)
                {
                    if (colors.Count == 3) return colors;
                    Color clr = bitmap.GetPixel(x, y);

                    byte color = GetC64Color(clr.R, clr.G, clr.B);

                    if (color!=0)
                    {
                        bool found = false;
                        for (int c = 0; c < colors.Count; c++)
                        {
                            if (colors[c] == color)
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found) colors.Add(color);

                    }
                    /*
                                        for (byte i = 1; i < c64ColorsRgb.Length; i++)
                                        {
                                            if (c64ColorsRgb[i].R == clr.R && c64ColorsRgb[i].G == clr.G && c64ColorsRgb[i].B == clr.B)
                                            {
                                                bool found = false;
                                                for (int c = 0; c < colors.Count; c++)
                                                {
                                                    if (colors[c] == i)
                                                    {
                                                        found = true;
                                                        break;
                                                    }
                                                }

                                                if (!found) colors.Add(i);
                                            }
                                        }
                    */
                }
            }

            return colors;
        }


        private static void GetColors(Bitmap bitmap, List<Rgb> rgbArray, int[] count)
        {
            for (int y = 0; y < 96; y++)
            {
                for (int x = 0; x < 160; x++)
                {
                    Color clr = bitmap.GetPixel(x, y);

                    int colorIndex = -1;
                    for (int i = 0; i < rgbArray.Count; i++)
                    {
                        if (rgbArray[i].R == clr.R && rgbArray[i].G == clr.G && rgbArray[i].B == clr.B)
                        {
                            colorIndex = i;
                        }
                    }

                    if (colorIndex >= 0)
                    {
                        count[colorIndex]++;
                    }
                    else
                    {
                        Rgb rgbColor = new Rgb();
                        rgbColor.R = clr.R;
                        rgbColor.G = clr.G;
                        rgbColor.B = clr.B;
                        rgbArray.Add(rgbColor);

                    }
                }
            }
        }
    }
}



//using System;
//using System.Collections.Generic;
//using System.Drawing;
//using System.IO;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;

//namespace C64VideoConverter
//{
//    class Program
//    {
//        static void Main(string[] args)
//        {
//            string filePath = args[0];

//            if (args[0] == "a")
//            {
//                filePath = args[1];
//                Bins2Images(filePath);
//            }
//            else if (args[0] == "d")
//            {
//                filePath = args[1];
//                string outputFilePath = args[2];
//                int count = Convert.ToInt32(args[3]);
//                ProcessDupImages(filePath, outputFilePath, count);
//            }
//            else if (args[0] == "g")
//            {
//                filePath = args[1];
//                GeneratePattern(filePath);
//            }
//            else
//            {
//                if (args.Length > 2)
//                {
//                    string outputFile = args[1];
//                    int skip = Convert.ToInt32(args[2]);
//                    ProcessImages(filePath, "Scene", outputFile, skip);
//                }
//                else if (args.Length > 1)
//                {
//                    string outputFile = args[1];
//                    ProcessImage(filePath, outputFile);
//                }
//                else
//                {
//                    Bin2Image(filePath);
//                }

//            }
//        }

//        private static void GeneratePattern(string filePath)
//        {
//            FileStream fileStream = File.OpenWrite(filePath);

//            ulong f = 0;
//            ulong bPrev = 0;
//            ulong b = 1;
//            int i = 0;
//            while (i < 240)
//            {
//                f = b + bPrev;
//                bPrev = b;
//                b = f;

//                fileStream.WriteByte(Convert.ToByte((f >> 56) & 255));
//                fileStream.WriteByte(Convert.ToByte((f >> 48) & 255));
//                fileStream.WriteByte(Convert.ToByte((f >> 40) & 255));
//                fileStream.WriteByte(Convert.ToByte((f >> 32) & 255));
//                fileStream.WriteByte(Convert.ToByte((f >> 24) & 255));
//                fileStream.WriteByte(Convert.ToByte((f >> 16) & 255));
//                fileStream.WriteByte(Convert.ToByte((f >> 8) & 255));
//                fileStream.WriteByte(Convert.ToByte(f & 255));
//                i = i + 1;
//            }

//            fileStream.Close();
//        }

//        /*
//        static void Bin2Image(string filePath)
//        {
//            byte[] img = File.ReadAllBytes(filePath);
//            int currentByte = 0;
//            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
//            int[] shiftValue = { 6, 4, 2, 0 };

//            Bitmap flag = new Bitmap(160, 96);
//            for (int y = 0; y < flag.Height; y++)
//            {
//                for (int x = 0; x < flag.Width; x++)
//                {
//                    int mask = pixelMask[x % 4];
//                    int shift = shiftValue[x % 4];
//                    int color = (img[currentByte] & mask) >> shift;
//                    if (color == 0) flag.SetPixel(x, y, Color.Black);
//                    if (color == 1) flag.SetPixel(x, y, Color.DarkGray);
//                    if (color == 2) flag.SetPixel(x, y, Color.LightGray);
//                    if (color == 3) flag.SetPixel(x, y, Color.White);
//                    if (x % 4 == 3) currentByte++;
//                }                    
//            }

//            flag.Save(filePath + ".bmp");
//        }

//        */

//        static void Bins2Images(string filePath)
//        {
//            byte[] imgsAll = File.ReadAllBytes(filePath);
//            byte[] img = new byte[3840];
//            for (long index = 0; index < imgsAll.Length; index = index + 3840)
//            {
//                Array.Copy(imgsAll, index, img, 0, 3840);
//                Bitmap bm = Bin2ImageFB(img);
//                bm.Save("out\\scene" + index + ".png");
//            }
//        }

//        static void Bin2Image(string filePath)
//        {
//            byte[] img = File.ReadAllBytes(filePath);

//            Bitmap flag = Bin2ImageFB(img);
//            flag.Save(filePath + ".png");
//        }

//        static Bitmap Bin2ImageFB(byte[] img)
//        {
//            Bitmap flag = new Bitmap(160, 96);
//            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
//            int[] shiftValue = { 6, 4, 2, 0 };

//            for (int y = 0; y < flag.Height; y++)
//            {
//                int row = (y / 8);
//                for (int x = 0; x < flag.Width; x++)
//                {
//                    int column = (x / 4);
//                    int currentByte = row * 320 + (y % 8) + column * 8;
//                    int mask = pixelMask[x % 4];
//                    int shift = shiftValue[x % 4];
//                    int color = (img[currentByte] & mask) >> shift;
//                    if (color == 0) flag.SetPixel(x, y, Color.Black);
//                    if (color == 1) flag.SetPixel(x, y, Color.DarkGray);
//                    if (color == 2) flag.SetPixel(x, y, Color.LightGray);
//                    if (color == 3) flag.SetPixel(x, y, Color.White);
//                }
//            }

//            return flag;
//        }

//        static void ProcessDupImages(string inputFile, string outputFile, int count)
//        {
//            FileStream fileStream = File.OpenWrite(outputFile);
//            Bitmap bitmap = new Bitmap(inputFile);
//            byte[] converted = ConvertBitmapActual(bitmap);

//            for (int i = 0; i < count; i++)
//            {
//                fileStream.Write(converted, 0, converted.Length);
//            }

//            fileStream.Close();
//        }


//        static void ProcessImages(string filePath, string filePrefix, string outputFile, int skip)
//        {
//            FileStream fileStream = File.OpenWrite(outputFile);

//            int i = 1;

//            while (true)
//            {
//                string currentFileName = String.Format("{0}{1}.png", filePrefix, i.ToString().PadLeft(5, '0'));
//                string fullFilePath = String.Format("{0}\\{1}", filePath, currentFileName);
//                Console.Out.WriteLine("Processing : " + fullFilePath);
//                try
//                {
//                    Bitmap bitmap = new Bitmap(fullFilePath);
//                    byte[] converted = ConvertBitmapActual(bitmap);
//                    fileStream.Write(converted, 0, converted.Length);
//                }
//                catch (Exception ex)
//                {
//                    break;
//                }
//                i = i + skip;
//            }
//        }

//        static void ProcessImage(string filePath, string outputFile)
//        {

//            Console.Out.WriteLine("Processing : " + filePath);
//            FileStream fileStream = File.OpenWrite(outputFile);

//            Bitmap bitmap = new Bitmap(filePath);
//            byte[] converted = ConvertBitmapActual(bitmap);
//            fileStream.Write(converted, 0, converted.Length);
//            fileStream.Close();
//        }

//        //const int FrameSize = (160 * 100) / 4;
//        const int FrameSize = (320 * 12);

//        /*
//        const float black = 0;
//        const float dark_gray = 10/32;
//        const float light_gray = 20/32;
//        const float white = 32/32;
//        */


//        const float black = 0;
//        const float dark_gray = 8.0f / 32;
//        const float light_gray = 16.0f / 32;
//        const float white = 24.0f / 32;



//        static byte[] ConvertBitmapActual(Bitmap bitmap)
//        {
//            byte[] generated = new byte[FrameSize];
//            int[] pixelMask = { 0xC0, 0x30, 0x0C, 0x03 };
//            int[] shiftValue = { 6, 4, 2, 0 };


//            for (int y = 0; y < 96; y++)
//            {
//                int row = (y / 8);
//                for (int x = 0; x < 160; x++)
//                {
//                    int column = (x / 4);
//                    int color = 0;
//                    Color clr = bitmap.GetPixel(x, y);

//                    float brightness = clr.GetBrightness();

//                    if (brightness < dark_gray)
//                    {
//                        color = 0;
//                    }
//                    else if (brightness >= dark_gray && brightness < light_gray)
//                    {
//                        color = 1;
//                    }
//                    else if (brightness >= light_gray && brightness < white)
//                    {
//                        color = 2;
//                    }
//                    else
//                    {
//                        color = 3;
//                    }

//                    int currentByte = row * 320 + (y % 8) + column * 8;
//                    int mask = pixelMask[x % 4];
//                    int shift = shiftValue[x % 4];
//                    generated[currentByte] = Convert.ToByte(generated[currentByte] | Convert.ToByte(mask & (color << shift)));
//                }
//            }

//            return generated;
//        }

//    }
//}

