|
| 1 | +namespace SpacedTextPlugin |
| 2 | +{ |
| 3 | + using System; |
| 4 | + using System.Collections.Generic; |
| 5 | + using System.Drawing; |
| 6 | + using System.Drawing.Drawing2D; |
| 7 | + using System.Drawing.Imaging; |
| 8 | + using System.Drawing.Text; |
| 9 | + using PaintDotNet; |
| 10 | + using SpacedTextPlugin.Data; |
| 11 | + using SpacedTextPlugin.Interop; |
| 12 | + |
| 13 | + internal class Renderer : IDisposable |
| 14 | + { |
| 15 | + private readonly Rectangle selectionBounds; |
| 16 | + private readonly Font font; |
| 17 | + private readonly Bitmap image; |
| 18 | + private readonly Graphics graphics; |
| 19 | + private readonly ImageAttributes imageAttributes; |
| 20 | + |
| 21 | + private readonly Settings settings; |
| 22 | + |
| 23 | + public Renderer(Settings settings, PdnRegion selectionRegion) |
| 24 | + { |
| 25 | + //convert to AA space |
| 26 | + selectionBounds = selectionRegion.GetBoundsInt(); |
| 27 | + var scaledBounds = selectionBounds.Multiply(settings.AntiAliasLevel); |
| 28 | + font = settings.GetAntiAliasSizeFont(); |
| 29 | + image = new Bitmap(scaledBounds.Width, scaledBounds.Height); |
| 30 | + graphics = Graphics.FromImage(image); |
| 31 | + graphics.Clear(Color.Black); |
| 32 | + graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; |
| 33 | + |
| 34 | + this.settings = settings; |
| 35 | + |
| 36 | + //map color black to transparent |
| 37 | + ColorMap[] colorMap = { |
| 38 | + new ColorMap |
| 39 | + { |
| 40 | + OldColor = Color.Black, |
| 41 | + NewColor = Color.Transparent |
| 42 | + } |
| 43 | + }; |
| 44 | + imageAttributes = new ImageAttributes(); |
| 45 | + imageAttributes.SetRemapTable(colorMap); |
| 46 | + } |
| 47 | + |
| 48 | + public Bitmap Draw(IEnumerable<LineData> lines) |
| 49 | + { |
| 50 | + foreach (var line in lines) |
| 51 | + { |
| 52 | + //create bitmap for line |
| 53 | + using (var lineImage = new Bitmap(line.TextSize.Width, line.TextSize.Height)) |
| 54 | + { |
| 55 | + var lineGraphics = Graphics.FromImage(lineImage); |
| 56 | + |
| 57 | + if (settings.TextAlign != Constants.TextAlignmentOptions.Justify) |
| 58 | + { |
| 59 | + PInvoked.TextOut(lineGraphics, line.Text, 0, 0, font, settings.LetterSpacing); |
| 60 | + } |
| 61 | + else |
| 62 | + { |
| 63 | + Justify(line, lineGraphics); |
| 64 | + } |
| 65 | + |
| 66 | + //draw line bitmap to image |
| 67 | + graphics.DrawImage(lineImage, |
| 68 | + new Rectangle( |
| 69 | + line.LineBounds.Location, |
| 70 | + lineImage.Size |
| 71 | + ), /* destination rect */ |
| 72 | + 0, 0, /* source coordinates */ |
| 73 | + lineImage.Width, |
| 74 | + lineImage.Height, |
| 75 | + GraphicsUnit.Pixel, |
| 76 | + imageAttributes |
| 77 | + ); |
| 78 | + |
| 79 | +#if DEBUG |
| 80 | + //draw rectangles |
| 81 | + graphics.DrawRectangle(Pens.White, line.LineBounds); |
| 82 | + graphics.DrawLine(Pens.Gray, |
| 83 | + line.LineBounds.X, |
| 84 | + line.LineBounds.Y + line.TextSize.Height / 2, |
| 85 | + line.LineBounds.X + line.TextSize.Width, |
| 86 | + line.LineBounds.Y + line.TextSize.Height / 2 |
| 87 | + ); |
| 88 | +#endif |
| 89 | + lineGraphics.Dispose(); |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + //create selection-sized bitmap |
| 94 | + var resultImage = new Bitmap(selectionBounds.Width, selectionBounds.Height); |
| 95 | + var resultGraphics = Graphics.FromImage(resultImage); |
| 96 | + resultGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic; |
| 97 | + resultGraphics.DrawImage(image, 0, 0, selectionBounds.Width, selectionBounds.Height); |
| 98 | + |
| 99 | + return resultImage; |
| 100 | + } |
| 101 | + |
| 102 | + private void Justify(LineData line, Graphics lineGraphics) |
| 103 | + { |
| 104 | + var lineTextWithoutSpaces = line.Text.Replace(Constants.Space, string.Empty); |
| 105 | + var lineSizeWithoutSpaces = PInvoked.MeasureString(lineGraphics, lineTextWithoutSpaces, font, |
| 106 | + settings.LetterSpacing); |
| 107 | + var spaceWidth = (line.TextSize.Width - lineSizeWithoutSpaces.Width) / |
| 108 | + Math.Max((line.Text.Length - lineTextWithoutSpaces.Length), 1); |
| 109 | + if (spaceWidth > font.Size * 3) |
| 110 | + { |
| 111 | + PInvoked.TextOut(lineGraphics, line.Text, 0, 0, font, settings.LetterSpacing); |
| 112 | + } |
| 113 | + else |
| 114 | + { |
| 115 | + var x = 0; |
| 116 | + |
| 117 | + foreach (string word in line.Text.Split(Constants.SpaceChar)) |
| 118 | + { |
| 119 | + var wordSize = PInvoked.MeasureString(lineGraphics, word, font, settings.LetterSpacing); |
| 120 | + PInvoked.TextOut(lineGraphics, word, x, 0, font, settings.LetterSpacing); |
| 121 | + x += wordSize.Width + spaceWidth; |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + public void Dispose() |
| 127 | + { |
| 128 | + Dispose(true); |
| 129 | + GC.SuppressFinalize(this); |
| 130 | + } |
| 131 | + |
| 132 | + protected virtual void Dispose(bool isDisposing) |
| 133 | + { |
| 134 | + graphics.Dispose(); |
| 135 | + image.Dispose(); |
| 136 | + } |
| 137 | + } |
| 138 | +} |
0 commit comments