public static byte[] ReduceLine(Color32[] line, Color[] palette,Dictionary<int,int> dic=null)
		{
			var res = new byte[line.Length];
			if (dic == null)
				dic = new Dictionary<int, int>(); // Color, index
			else
				if (dic.Count > 4096) dic.Clear();
			var ac = -1;
			byte ai = 0;
			for (var f = 0; f < line.Length; f++)
			{
				var c = ((Color)line[f]).ToArgb();
				if (c == ac) res[f] = ai;
				if (!dic.ContainsKey(c))
				{
					var i = ((Color)line[f]).NearestColor(palette);
					dic[c] = i;
					ac = c;
					ai = (byte)i;
					res[f] = ai;
				}
				else
					res[f] = (byte)dic[c];
			}
			return res;
		}
		public static Color32 operator <<(Color32 a, int b)
		{
			var res = new Color32();
			res.A = 255;
			res.R = (byte)(a.R << b);
			res.G = (byte)(a.G << b);
			res.B = (byte)(a.B << b);
			return res;
		}
		public static void Pixels32ToLine(this BitmapData bmpdata, int line, Color32[] pixels)
		{
			var ptr = bmpdata.ScanLine(line);
			Pixels32ToLine(ptr, pixels);
		}
		public static void PixelsToBitmap32(this Bitmap image, Color32[][] pixels)
		{
			var sz = image.Size;
			var szpx = new Size(pixels[0].Length, pixels.Length);
			if (sz != szpx) throw new ArgumentException("Bad size error");
			var r1 = new Rectangle(Point.Empty, sz);
			var bmpdata = image.LockBits(new Rectangle(Point.Empty, sz), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
			var linea = bmpdata.Scan0;
			foreach (var l in pixels)
			{
				Pixels32ToLine(linea, l);
				linea += bmpdata.Stride;
			}
			image.UnlockBits(bmpdata);
		}
		public static void Pixels32ToLine(IntPtr line, Color32[] pixels)
		{
			GCHandle pinnedArray = GCHandle.Alloc(pixels, GCHandleType.Pinned);
			IntPtr pointer = pinnedArray.AddrOfPinnedObject();
			CopyMemory(line, pointer, (uint)pixels.Length * 4);
			pinnedArray.Free();
		}
		public static Color32[] LineToPixels32(this BitmapData bmpdata, IntPtr line)
		{
			var l = new Color32[bmpdata.Width];
			GCHandle pinnedArray = GCHandle.Alloc(l, GCHandleType.Pinned);
			IntPtr pointer = pinnedArray.AddrOfPinnedObject();
			CopyMemory(pointer, line, (uint)bmpdata.Width * 4);
			pinnedArray.Free();
			return l;
		}
		public static Color32 BitWideMask(int bit,int code=8)
		{
			var res = new Color32();
			res.A = 255;
			if (bit < 0) return res;
			if ((code & 0x4) != 0) res.R = (byte)((2 << bit)-1);
			if ((code & 0x2) != 0) res.G = (byte)((2 << bit)-1);
			if ((code & 0x1) != 0) res.B = (byte)((2 << bit)-1);
			return res;
		}
		public static Color32 BitMask(int bit,int code=7)
		{
			var res = new Color32();
			res.A = 255;
			if (bit > 7) return res;
			if ((code&0x4)!=0) res.R = (byte)(1 << bit);
			if ((code & 0x2) != 0) res.G = (byte)(1 << bit);
			if ((code & 0x1) != 0) res.B = (byte)(1 << bit);
			return res;
		}
		public static Color32 operator >>(Color32 a, int b)
		{
			var res = new Color32();
			res.A = 255;
			res.R = (byte)(a.R >> b);
			res.G = (byte)(a.G >> b);
			res.B = (byte)(a.B >> b);
			return res;
		}