Пример #1
0
        public System.Drawing.Bitmap TextToBitmap(string text, out Size2F size, RawColor4 bgcolor, d2.TextAntialiasMode aamode, int maxWidth = 1000, int maxHeight = 1000)
        {
            var sz          = GetTextSize(text, maxWidth, maxHeight);
            int pixelWidth  = (int)(sz.Width * 2);
            int pixelHeight = (int)(sz.Height * 2);

            var d2dRenderTarget = new Bitmap1(d2dContext, new Size2(pixelWidth, pixelHeight), d2dBitmapProps);

            if (d2dContext.Target != null)
            {
                d2dContext.Target.Dispose();
            }
            d2dContext.Target = d2dRenderTarget; // associate bitmap with the d2d context

            // Draw Text
            TextLayout textLayout = new TextLayout(dwFactory, text, textFormat, pixelWidth, pixelHeight);

            //d2dContext.TextRenderingParams = new RenderingParams(dwFactory, 1, 0, 0, PixelGeometry.Flat, renderingMode);
            d2dContext.TextAntialiasMode = aamode;

            d2dContext.BeginDraw();
            d2dContext.Clear(bgcolor);
            d2dContext.DrawTextLayout(new RawVector2(0, 0), textLayout, textBrush, DrawTextOptions.EnableColorFont);
            d2dContext.EndDraw();

            size = new Size2F(textLayout.Metrics.Width, textLayout.Metrics.Height);

            textLayout.Dispose();

            // Copy to MemoryStream
            var stream  = new MemoryStream();
            var encoder = new wic.PngBitmapEncoder(imagingFactory);

            encoder.Initialize(stream);

            var bitmapFrameEncode = new wic.BitmapFrameEncode(encoder);

            bitmapFrameEncode.Initialize();
            bitmapFrameEncode.SetSize(pixelWidth, pixelHeight);
            bitmapFrameEncode.SetPixelFormat(ref wicPixelFormat);

            // this is the trick to write D2D1 bitmap to WIC
            var imageEncoder = new wic.ImageEncoder(imagingFactory, d2dDevice);
            var imageParam   = new wic.ImageParameters(d2PixelFormat, dpi, dpi, 0, 0, pixelWidth, pixelHeight);

            imageEncoder.WriteFrame(d2dRenderTarget, bitmapFrameEncode, imageParam);
            bitmapFrameEncode.Commit();
            encoder.Commit();

            imageEncoder.Dispose();
            encoder.Dispose();
            bitmapFrameEncode.Dispose();
            d2dRenderTarget.Dispose();

            // Convert To Bitmap
            byte[] data = stream.ToArray();
            stream.Seek(0, SeekOrigin.Begin);
            var bmp = new System.Drawing.Bitmap(stream);

            stream.Dispose();

            return(bmp);
        }
Пример #2
0
        // todo: use this renderer; it's much better for monochrome fonts. for color there's still no better solution i know of.
        //// https://stackoverflow.com/questions/9080231/how-to-save-geometry-as-image
        //public static GenerateEmojiBitmapResults GenerateFontMap2(string fontName, int WidthAndHeight, string outputFileName)
        //{
        //  GlyphTypeface font;
        //  if (File.Exists(fontName))
        //  {
        //    font = new GlyphTypeface(new Uri(fontName));
        //  }
        //  else
        //  {
        //    Typeface face = new Typeface(fontName);
        //    face.TryGetGlyphTypeface(out font);
        //  }

        //  //int ColumnCount = 10;
        //  //int MaxDrawCount = 30; // use int.MaxValue to draw them all
        //  double fontSize = WidthAndHeight;
        //  // the height of each cell has to include over/underhanging glyphs
        //  SizeF cellSize = new SizeF((float)fontSize, (float)(fontSize * font.Height));

        //  var Glyphs = from glyphIndex in font.CharacterToGlyphMap.Values
        //               select font.GetGlyphOutline(glyphIndex, fontSize, 1d);

        //  int ColumnCount = (int)Math.Ceiling(Math.Sqrt(Glyphs.Count()));

        //  // now create the visual we'll draw them to
        //  DrawingVisual viz = new DrawingVisual();
        //  //int drawCount = -1;
        //  using (DrawingContext dc = viz.RenderOpen())
        //  {
        //    foreach (var g in Glyphs)
        //    {
        //      drawCount++;
        //      if (g.IsEmpty()) continue; // don't draw the blank ones
        //                                 // center horizontally in the cell
        //      double xOffset = (drawCount % ColumnCount) * cellSize.Width + cellSize.Width / 2d - g.Bounds.Width / 2d;
        //      // place the character on the baseline of the cell
        //      double yOffset = (drawCount / ColumnCount) * cellSize.Height + fontSize * font.Baseline;
        //      dc.PushTransform(new TranslateTransform(xOffset, yOffset));
        //      dc.DrawGeometry(System.Windows.Media.Brushes.Red, null, g);
        //      dc.Pop(); // get rid of the transform
        //    }
        //  }

        //  int RowCount = drawCount / ColumnCount;
        //  if (drawCount % ColumnCount != 0)
        //    RowCount++; // to include partial rows
        //  int bitWidth = (int)Math.Ceiling((double)(cellSize.Width * ColumnCount));
        //  int bitHeight = (int)Math.Ceiling((double)(cellSize.Height * RowCount));
        //  RenderTargetBitmap bmp = new RenderTargetBitmap(
        //                                                  bitWidth, bitHeight,
        //                                                  96, 96,
        //                                                  PixelFormats.Pbgra32);
        //  bmp.Render(viz);

        //  PngBitmapEncoder encoder = new PngBitmapEncoder();
        //  encoder.Frames.Add(BitmapFrame.Create(bmp));
        //  using (FileStream file = new FileStream(outputFileName, FileMode.Create))
        //    encoder.Save(file);
        //}



        public static GenerateEmojiBitmapResults GenerateEmojiBitmap(string fontName, int cellWidth, int cellHeight,
                                                                     float additionalScale, int shiftX, int shiftY, IEnumerable <EmojiInfo> codepointsToInclude,
                                                                     System.Drawing.Color[] backgroundPalette, System.Drawing.Color[] textPalette, float?aspectToleranceFromTarget, bool tryToFit,
                                                                     System.Windows.FontStyle fontStyle, System.Windows.FontWeight fontWeight, System.Windows.FontStretch fontStretch,
                                                                     bool strictGlyphChecking, d2.TextAntialiasMode aaMode)
        {
            System.Windows.Media.FontFamily fm = new System.Windows.Media.FontFamily(fontName);
            System.Windows.Media.Typeface   tf = new System.Windows.Media.Typeface(fm, fontStyle, fontWeight, fontStretch);
            PetsciiMapgen.ProgressReporter  pr = new PetsciiMapgen.ProgressReporter((ulong)codepointsToInclude.Count() * (ulong)backgroundPalette.Length * (ulong)textPalette.Length);
            if (!tf.TryGetGlyphTypeface(out System.Windows.Media.GlyphTypeface gtf))
            {
                PetsciiMapgen.Log.WriteLine("!!!!!!!!!! FONT FAMILY HAS NO GLYPH MAP; you will end up with unsupported glyphs in the map.");
                // throw new Exception();
            }

            // select codepoints to actually use
            PetsciiMapgen.Utils.ValueRangeInspector rangeX          = new PetsciiMapgen.Utils.ValueRangeInspector();
            PetsciiMapgen.Utils.ValueRangeInspector rangeY          = new PetsciiMapgen.Utils.ValueRangeInspector();
            PetsciiMapgen.Utils.ValueRangeInspector allAspects      = new PetsciiMapgen.Utils.ValueRangeInspector();
            PetsciiMapgen.Utils.ValueRangeInspector selectedAspects = new PetsciiMapgen.Utils.ValueRangeInspector();
            int rejectedBecauseNotInTypeface = 0;
            int rejectedBecauseAspect        = 0;

            int   targetWidth  = cellWidth;
            int   targetHeight = cellHeight;
            float targetAspect = (float)targetWidth / targetHeight;

            EmojiTest.Direct2DText dt = new EmojiTest.Direct2DText();
            dt.SetFont(fontName, targetHeight);

            var emoji = codepointsToInclude.Select(e =>
            {
                pr.Visit();
                GlyphData ret = new GlyphData();
                ret.info      = e;
                //ret.str = char.ConvertFromUtf32(cp);
                var sz     = dt.GetTextSize(ret.info.str);
                ret.width  = sz.Width;
                ret.height = sz.Height;
                rangeX.Visit(ret.width);
                rangeY.Visit(ret.height);
                allAspects.Visit(ret.width / ret.height);
                ret.scaleNeeded = 1;
                if (tryToFit)
                {
                    if (ret.height > 0 && ret.width > 0)
                    {
                        float scaleNeededY = (float)targetHeight / ret.height;// factor to match target
                        float scaleNeededX = (float)targetWidth / ret.width;
                        ret.scaleNeeded    = Math.Min(scaleNeededX, scaleNeededY);
                    }
                    else
                    {
                        ret.scaleNeeded = -1;
                    }
                }
                return(ret);
            })
                        .Where(o =>
            {
                if (o.info.forceInclude)
                {
                    return(true);
                }
                if (o.info.str == "\r" || o.info.str == "\n")
                {
                    return(false);
                }
                if (gtf != null)
                {
                    if (!gtf.CharacterToGlyphMap.ContainsKey(o.info.cps[0]))
                    {
                        rejectedBecauseNotInTypeface++;
                        if (strictGlyphChecking)
                        {
                            return(false);
                        }
                    }
                }
                float aspect = o.width / o.height;
                float da     = Math.Abs(aspect - targetAspect);
                if (aspectToleranceFromTarget.HasValue && da > aspectToleranceFromTarget)
                {
                    rejectedBecauseAspect++;
                    return(false);
                }

                selectedAspects.Visit(aspect);
                return(true);
            })
                        .OrderBy(o => o.scaleNeeded).ToArray();

            PetsciiMapgen.Log.WriteLine("EMOJI font encountered aspect ratios between {0}", allAspects);
            PetsciiMapgen.Log.WriteLine("Chars rejected because they don't have glyphs in this typeface: {0:N0}", rejectedBecauseNotInTypeface);
            PetsciiMapgen.Log.WriteLine("Chars rejected because aspect ratio out of range: {0:N0}", rejectedBecauseAspect);
            if (aspectToleranceFromTarget.HasValue)
            {
                PetsciiMapgen.Log.WriteLine("EMOJI font allowed aspect ratios between {0}", selectedAspects);
            }

            int totalCharCount = emoji.Count() * backgroundPalette.Length * textPalette.Length;
            int scaleChanges   = 0;

            int columns   = (int)Math.Ceiling(Math.Sqrt(totalCharCount));
            int rows      = columns;// we're aiming for square bitmap.
            int imgWidth  = columns * targetWidth;
            int imgHeight = rows * targetHeight;

            List <GlyphData> fullEmoji = new List <GlyphData>(totalCharCount);

            if (emoji.Length < 2)
            {
                throw new Exception("NOt enough glyphs to generate anything meaningful.");
            }

            foreach (var backgroundColor in backgroundPalette)
            {
                foreach (var textColor in textPalette)
                {
                    var bmp = new System.Drawing.Bitmap(imgWidth, imgHeight);
                    using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
                    {
                        float lastScale = 0;
                        //int iemoji = 0;
                        var pr2 = new PetsciiMapgen.ProgressReporter((ulong)emoji.Count());
                        //foreach (var e in emoji)
                        for (int iemoji = 0; iemoji < emoji.Length; ++iemoji)
                        {
                            var e = emoji[iemoji];
                            pr2.Visit();
                            if (e.scaleNeeded <= 0)
                            {
                                continue;
                            }
                            if (Math.Abs(lastScale - e.scaleNeeded) > 0.001)
                            {
                                scaleChanges++;
                                dt.SetFont(fontName, targetHeight * e.scaleNeeded * additionalScale);
                            }

                            //SharpDX.Size2F sz;
                            var n = new GlyphData(e);
                            fullEmoji.Add(n);

                            RawColor4 bg = new RawColor4(backgroundColor.R / 255.0f, backgroundColor.G / 255.0f, backgroundColor.B / 255.0f, 1);
                            dt.SetColor(textColor);
                            n.bmp = dt.TextToBitmap(n.info.str, out n.bmpSize, bg, aaMode);

                            // offset where to blit from, so it's centered.
                            int ox = (int)((n.bmpSize.Width - targetWidth) / 2);
                            int oy = (int)((n.bmpSize.Height - targetHeight) / 2);
                            n.blitSourcRect = new System.Drawing.Rectangle(ox - shiftX, oy - shiftY, targetWidth, targetHeight);
                            n.bgColor       = backgroundColor;
                            n.textColor     = textColor;

                            //int y = iemoji / columns;
                            //int x = iemoji % columns;
                            //g.DrawImage(bmpChar,
                            //  new System.Drawing.Rectangle(x * targetWidth, y * targetHeight, targetWidth, targetHeight),
                            //  new System.Drawing.Rectangle(ox - shiftX, oy - shiftY, targetWidth, targetHeight), System.Drawing.GraphicsUnit.Pixel
                            //  );

                            //bmpChar.Dispose();
                            //iemoji++;
                        }
                    }
                }
            }

            PetsciiMapgen.Log.WriteLine("Scale changes: {0}", scaleChanges);
            PetsciiMapgen.Log.WriteLine("Total char count: {0}", fullEmoji.Count);
            PetsciiMapgen.Log.WriteLine("Image size to hold entire colored charset: {0}, {1}", imgWidth, imgHeight);

            GenerateEmojiBitmapResults rv = new GenerateEmojiBitmapResults();

            //rv.bmp = bmp;
            rv.columns  = columns;
            rv.rows     = rows;
            rv.AllCells = fullEmoji.ToArray();
            return(rv);
        }