Skip to content

Commit ff3f7f7

Browse files
authored
Merge pull request #8 from simmetric/featureNonRectangularSelection
Feature: non-rectangular selection
2 parents 5f941f3 + 1a06a40 commit ff3f7f7

File tree

12 files changed

+521
-243
lines changed

12 files changed

+521
-243
lines changed

SpacedText/Constants.cs renamed to SpacedText/Data/Constants.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
6-
7-
namespace SpacedTextPlugin
1+
namespace SpacedTextPlugin.Data
82
{
9-
using System.Diagnostics.PerformanceData;
10-
113
public class Constants
124
{
135
public enum Properties

SpacedText/Data/Extent.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
namespace SpacedTextPlugin.Data
2+
{
3+
using System.Drawing;
4+
5+
public struct Extent
6+
{
7+
public int VerticalPosition { get; private set; }
8+
public int Left { get; private set; }
9+
public int Right { get; private set; }
10+
public int Width { get; private set; }
11+
12+
public Point Start => new Point(Left, VerticalPosition);
13+
14+
public Point End => new Point(Right, VerticalPosition);
15+
16+
public Extent(int left, int right, int y)
17+
{
18+
Left = left;
19+
Right = right;
20+
Width = right - left;
21+
VerticalPosition = y;
22+
}
23+
24+
public Extent Multiply(int factor)
25+
{
26+
Left *= factor;
27+
Right *= factor;
28+
Width = Right - Left;
29+
VerticalPosition *= factor;
30+
31+
return this;
32+
}
33+
}
34+
}

SpacedText/Data/LineData.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace SpacedTextPlugin.Data
2+
{
3+
using System.Drawing;
4+
5+
public class LineData
6+
{
7+
public string Text { get; set; }
8+
public Rectangle LineBounds { get; set; }
9+
public Size TextSize { get; set; }
10+
}
11+
}

SpacedText/Data/Settings.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace SpacedTextPlugin.Data
2+
{
3+
using System.Drawing;
4+
5+
class Settings
6+
{
7+
public string Text { get; set; }
8+
public FontFamily FontFamily { get; set; }
9+
public int FontSize { get; set; }
10+
public double LetterSpacing { get; set; }
11+
public double LineSpacing { get; set; }
12+
public int AntiAliasLevel { get; set; }
13+
public FontStyle FontStyle { get; set; }
14+
public Constants.TextAlignmentOptions TextAlign { get; set; }
15+
16+
public Font GetFont()
17+
{
18+
return new Font(FontFamily, FontSize, FontStyle, GraphicsUnit.Pixel);
19+
}
20+
21+
public Font GetAntiAliasSizeFont()
22+
{
23+
return new Font(FontFamily, FontSize * AntiAliasLevel, FontStyle, GraphicsUnit.Pixel);
24+
}
25+
}
26+
}

SpacedText/ExtensionMethods.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace SpacedTextPlugin
2+
{
3+
using System.Drawing;
4+
5+
public static class ExtensionMethods
6+
{
7+
public static Rectangle Multiply(this Rectangle r, int factor)
8+
{
9+
return new Rectangle(
10+
r.X * factor,
11+
r.Y * factor,
12+
r.Width * factor,
13+
r.Height * factor);
14+
}
15+
16+
public static Size Multiply(this Size s, int factor)
17+
{
18+
return new Size(
19+
s.Width * factor,
20+
s.Height * factor);
21+
}
22+
}
23+
}

SpacedText/Interop.cs renamed to SpacedText/Interop/Interop.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
6-
7-
namespace SpacedTextPlugin
1+
namespace SpacedTextPlugin.Interop
82
{
3+
using System;
94
using System.Drawing;
105
using System.Runtime.InteropServices;
116

12-
internal class Interop
7+
internal static class Interop
138
{
149
[DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
1510
public static extern int SetTextCharacterExtra(IntPtr hdc, int nCharExtra);

SpacedText/PInvoked.cs renamed to SpacedText/Interop/PInvoked.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
namespace SpacedTextPlugin
1+
namespace SpacedTextPlugin.Interop
22
{
33
using System;
44
using System.Drawing;
55
using System.Drawing.Drawing2D;
66

7-
public class PInvoked
7+
internal static class PInvoked
88
{
99
public static void TextOut(Graphics g, string text, int x, int y, Font font, double letterSpacing)
1010
{
1111
g.PixelOffsetMode = PixelOffsetMode.Half;
12-
IntPtr hdc = default(IntPtr);
1312
IntPtr fontPtr = default(IntPtr);
1413
try
1514
{
1615
//Grab the Graphic object's handle
17-
hdc = g.GetHdc();
16+
IntPtr hdc = g.GetHdc();
1817
//Set the current GDI font
1918
fontPtr = Interop.SelectObject(hdc, font.ToHfont());
2019
//Set the drawing surface background color
@@ -36,13 +35,12 @@ public static void TextOut(Graphics g, string text, int x, int y, Font font, dou
3635

3736
public static Size MeasureString(Graphics g, string text, Font font, double letterSpacing)
3837
{
39-
IntPtr hdc = default(IntPtr);
4038
IntPtr fontPtr = default(IntPtr);
4139
Size size = new Size();
4240
try
4341
{
4442
//Grab the Graphic object's handle
45-
hdc = g.GetHdc();
43+
IntPtr hdc = g.GetHdc();
4644
//Set the current GDI font
4745
fontPtr = Interop.SelectObject(hdc, font.ToHfont());
4846
//Set the kerning

SpacedText/Renderer.cs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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

Comments
 (0)