using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace PrinterDemo
{

    [StructLayout(LayoutKind.Sequential)]
    struct BitmapWin32
    {
        public int bmType;
        public int bmWidth;
        public int bmHeight;
        public int bmWidthBytes;
        public ushort bmPlanes;
        public ushort bmBitsPixel;
        public IntPtr bmBits;
    }


    /**
    * Convert an image into a format that can be used by the Cyberview Scanner.
    */
    class BitmapConvert : IDisposable
    {

        public IntPtr BitmapPtr
        {
            get;
        }

        private IntPtr m_pixelData;

        public BitmapConvert(string fileName)
        {

            Bitmap src = new Bitmap(fileName);

            var bitmapInfo = new BitmapWin32();
            bitmapInfo.bmType = 0;
            bitmapInfo.bmHeight = src.Height;
            bitmapInfo.bmWidth = src.Width;   //This should probably be 576
            bitmapInfo.bmWidthBytes = src.Width / 8;
            bitmapInfo.bmPlanes = 1;
            bitmapInfo.bmBitsPixel = 1;

            byte[] bitmapData = ConvertPixels(src);

            m_pixelData = Marshal.AllocHGlobal(bitmapData.Length);
            Marshal.Copy(bitmapData, 0, m_pixelData, bitmapData.Length);
            bitmapInfo.bmBits = m_pixelData;

            var size = Marshal.SizeOf<BitmapWin32>();
            BitmapPtr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr<BitmapWin32>(bitmapInfo, BitmapPtr, false);

        }

        private static byte[] ConvertPixels(Bitmap bmp)
        {
            int pixels = bmp.Height * bmp.Width;
            int bytes = pixels / 8;

            byte[] bits = new byte[bytes];
            for (int i = 0; i < bytes; i++)
            {
                int x = (i * 8) % bmp.Width;
                int y = (i * 8) / bmp.Width;  

                bits[i] |= IsWhite(bmp, x + 0, y, 7);
                bits[i] |= IsWhite(bmp, x + 1, y, 6);
                bits[i] |= IsWhite(bmp, x + 2, y, 5);
                bits[i] |= IsWhite(bmp, x + 3, y, 4);
                bits[i] |= IsWhite(bmp, x + 4, y, 3);
                bits[i] |= IsWhite(bmp, x + 5, y, 2);
                bits[i] |= IsWhite(bmp, x + 6, y, 1);
                bits[i] |= IsWhite(bmp, x + 7, y, 0);

            }
            return bits;
        }

        /**
         * Return 0x01 if white, or 0x00 if not white
         */
        private static byte IsWhite(Bitmap bmp, int x, int y, int shift)
        {
            Color clr = bmp.GetPixel(x, y);
            var bit = clr.ToArgb() == Color.White.ToArgb() ? 1 : 0;
            return (byte)(bit << shift);
        }

        #region IDisposable Support
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {

                Marshal.FreeHGlobal(m_pixelData);
                Marshal.FreeHGlobal(BitmapPtr);
                disposedValue = true;
            }
        }

        ~BitmapConvert() {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(false);
         }

        // This code added to correctly implement the disposable pattern.
        public void Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion

    }
}
