public NxFont Load(string filePath, float height, float downSampleFactor, NxFontLoaderConfiguration loaderConfig)
		{
			if (loaderConfig == null)
			{
				throw new ArgumentNullException ("loaderConfig");
			}

			float fontScale;
			TransformViewport? transToVp = NxFont.SetupTransformViewport (height, loaderConfig.TransformToCurrentOrthogProjection, loaderConfig.Transform, out fontScale);

			var qfont = new NxFont();
			var internalConfig = new QFontLoaderConfiguration();		
			var fontData = new QFontData ();
			qfont.SetData (fontData);

			QFontDataInformation fontInfo = null;
			using (var fs = File.OpenRead (filePath))
			{
				fontInfo = fontData.LoadFromStream (fs);
			}
			var bitmapFiles = fontInfo.GenerateBitmapPageNames (filePath);

			var bitmapPages = new List<NxBitmap> ();
			foreach (var bitmapFileName in bitmapFiles)
			{
				// TODO : STREAM BASED REPLACEMENT 
				// https://support.microsoft.com/en-us/kb/814675
				// GDI+ require the bitmap files to be locked as indexed image
				// during the lifetime i.e. maybe reloaded from disk				
				using (var fs = File.OpenRead (bitmapFileName))	
				{
					var parent = new Bitmap (fs);
					var data = parent.LockBits (
							new Rectangle(0,0, parent.Width, parent.Height)
							,System.Drawing.Imaging.ImageLockMode.ReadWrite
							,parent.PixelFormat);
					var target = new QBitmapData (data);
					var qb = new NxBitmap (parent, target);
					bitmapPages.Add (qb);
				}
			}
			var glyphList = fontData.InitialiseQFontData (fontInfo, ref bitmapPages, downSampleFactor, internalConfig);

			if (loaderConfig.ShadowConfig != null)
			{
				qfont.DropShadow = Helper.BuildDropShadow<NxFont, NxBitmap> (
					bitmapPages,
					glyphList.ToArray (),
					loaderConfig.ShadowConfig,
					Helper.ToArray (fontInfo.CharSet),
					internalConfig.KerningConfig.alphaEmptyPixelTolerance);
			}
			fontData.InitialiseKerningPairs (fontInfo, bitmapPages, glyphList, internalConfig);

			if (loaderConfig.ShadowConfig != null)
				qfont.Options.DropShadowActive = true;
			if (transToVp != null)
				qfont.Options.TransformToViewport = transToVp;

			qfont.InitialiseGlyphRenderer(loaderConfig.CharacterOutput, loaderConfig.FontGlyphRenderer, loaderConfig.DropShadowRenderer);

			return qfont;
		}
		public NxFont (string fileName, float size, float height, FontStyle style, NxFontBuilderConfiguration config)
		{
			optionsStack = new ConcurrentStack<QFontRenderOptions> ();
			PrivateFontCollection pfc = new PrivateFontCollection();
			pfc.AddFontFile(fileName);
			var fontFamily = pfc.Families[0];

			if (!fontFamily.IsStyleAvailable(style))
				throw new ArgumentException("Font file: " + fileName + " does not support style: " +  style );

			if (config == null)
			{
				throw new ArgumentNullException ("config");
			}

			float fontScale;
			var transToVp = SetupTransformViewport (height, config.TransformToCurrentOrthogProjection, config.Transform, out fontScale);

			var internalConfig = new QFontBuilderConfiguration (config.AddDropShadow);
			internalConfig.SuperSampleLevels = config.SuperSampleLevels;
			if (internalConfig.ShadowConfig != null)
			{
				internalConfig.ShadowConfig.blurRadius = config.BlurRadius;
			}
			using(var font = new Font(fontFamily, size * fontScale * config.SuperSampleLevels, style)){
				var builder = new Builder<NxFont>(font, internalConfig);
				NxFont dropShadowFont;
				fontData = builder.BuildFontData(null, out dropShadowFont);
				DropShadow = dropShadowFont;
			}

			if (internalConfig.ShadowConfig != null)
				Options.DropShadowActive = true;
			if (transToVp != null)
				Options.TransformToViewport = transToVp;

			InitialiseGlyphRenderer(config.CharacterOutput, config.FontGlyphRenderer, config.DropShadowRenderer);
		}