2020-07-20 09:33:16 +12:00
#region License Information ( GPL v3 )
/ *
ShareX - A program that allows you to take screenshots and share any file type
2022-01-12 05:32:17 +13:00
Copyright ( c ) 2007 - 2022 ShareX Team
2020-07-20 09:33:16 +12:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
Optionally you can also view the license at < http : //www.gnu.org/licenses/>.
* /
#endregion License Information ( GPL v3 )
using ShareX.HelpersLib ;
using System.ComponentModel ;
using System.Drawing ;
using System.Drawing.Design ;
using System.Drawing.Drawing2D ;
namespace ShareX.ImageEffectsLib
{
2020-07-20 12:40:39 +12:00
[Description("Text")]
2020-07-20 09:33:16 +12:00
public class DrawTextEx : ImageEffect
{
2020-07-20 14:10:04 +12:00
[DefaultValue("Text"), Editor(typeof(NameParserEditor), typeof(UITypeEditor))]
public string Text { get ; set ; }
2020-07-20 15:25:38 +12:00
[DefaultValue(ContentAlignment.TopLeft), TypeConverter(typeof(EnumProperNameConverter))]
2020-07-20 09:33:16 +12:00
public ContentAlignment Placement { get ; set ; }
[DefaultValue(typeof(Point), "0, 0")]
public Point Offset { get ; set ; }
2020-07-21 05:03:49 +12:00
[DefaultValue(0)]
public int Angle { get ; set ; }
2020-08-16 07:10:17 +12:00
[DefaultValue(false), Description("If text size bigger than source image then don't draw it.")]
2020-07-20 09:33:16 +12:00
public bool AutoHide { get ; set ; }
private FontSafe fontSafe = new FontSafe ( ) ;
// Workaround for "System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
2020-07-20 10:24:07 +12:00
[DefaultValue(typeof(Font), "Arial, 36pt")]
2020-07-20 09:33:16 +12:00
public Font Font
{
get
{
return fontSafe . GetFont ( ) ;
}
set
{
using ( value )
{
fontSafe . SetFont ( value ) ;
}
}
}
[DefaultValue(typeof(Color), "235, 235, 235"), Editor(typeof(MyColorEditor), typeof(UITypeEditor)), TypeConverter(typeof(MyColorConverter))]
2020-07-21 05:19:51 +12:00
public Color Color { get ; set ; }
2020-07-20 09:33:16 +12:00
[DefaultValue(false)]
2020-07-21 05:19:51 +12:00
public bool UseGradient { get ; set ; }
2020-07-20 09:33:16 +12:00
[Editor(typeof(GradientEditor), typeof(UITypeEditor))]
2020-07-21 05:19:51 +12:00
public GradientInfo Gradient { get ; set ; }
2020-07-20 09:33:16 +12:00
2020-07-20 10:00:32 +12:00
[DefaultValue(false)]
2020-07-21 05:19:51 +12:00
public bool Outline { get ; set ; }
2020-07-20 10:00:32 +12:00
[DefaultValue(5)]
2020-07-21 05:19:51 +12:00
public int OutlineSize { get ; set ; }
2020-07-20 10:00:32 +12:00
[DefaultValue(typeof(Color), "235, 0, 0"), Editor(typeof(MyColorEditor), typeof(UITypeEditor)), TypeConverter(typeof(MyColorConverter))]
2020-07-21 05:19:51 +12:00
public Color OutlineColor { get ; set ; }
2020-07-20 10:00:32 +12:00
[DefaultValue(false)]
2020-07-21 05:19:51 +12:00
public bool OutlineUseGradient { get ; set ; }
2020-07-20 10:00:32 +12:00
[Editor(typeof(GradientEditor), typeof(UITypeEditor))]
2020-07-21 05:19:51 +12:00
public GradientInfo OutlineGradient { get ; set ; }
2020-07-20 10:00:32 +12:00
2020-07-20 10:24:07 +12:00
[DefaultValue(false)]
2020-07-21 05:19:51 +12:00
public bool Shadow { get ; set ; }
2020-07-20 10:24:07 +12:00
2020-07-20 16:00:43 +12:00
[DefaultValue(typeof(Point), "0, 5")]
2020-07-21 05:19:51 +12:00
public Point ShadowOffset { get ; set ; }
2020-07-20 16:00:43 +12:00
2020-07-20 10:24:07 +12:00
[DefaultValue(typeof(Color), "125, 0, 0, 0"), Editor(typeof(MyColorEditor), typeof(UITypeEditor)), TypeConverter(typeof(MyColorConverter))]
2020-07-21 05:19:51 +12:00
public Color ShadowColor { get ; set ; }
2020-07-20 10:24:07 +12:00
2020-07-20 16:00:43 +12:00
[DefaultValue(false)]
2020-07-21 05:19:51 +12:00
public bool ShadowUseGradient { get ; set ; }
2020-07-20 16:00:43 +12:00
[Editor(typeof(GradientEditor), typeof(UITypeEditor))]
2020-07-21 05:19:51 +12:00
public GradientInfo ShadowGradient { get ; set ; }
2020-07-20 10:24:07 +12:00
2020-07-20 09:33:16 +12:00
public DrawTextEx ( )
{
this . ApplyDefaultPropertyValues ( ) ;
2021-08-19 11:21:29 +12:00
Gradient = AddDefaultGradient ( ) ;
OutlineGradient = AddDefaultGradient ( ) ;
ShadowGradient = AddDefaultGradient ( ) ;
2020-07-20 09:33:16 +12:00
}
2021-08-19 11:21:29 +12:00
private GradientInfo AddDefaultGradient ( )
2020-07-20 09:33:16 +12:00
{
2021-08-19 11:21:29 +12:00
GradientInfo gradientInfo = new GradientInfo ( ) ;
2020-07-20 10:00:32 +12:00
gradientInfo . Type = LinearGradientMode . Horizontal ;
2020-07-20 09:33:16 +12:00
switch ( RandomFast . Next ( 0 , 2 ) )
{
case 0 :
2020-07-20 10:00:32 +12:00
gradientInfo . Colors . Add ( new GradientStop ( Color . FromArgb ( 0 , 187 , 138 ) , 0f ) ) ;
gradientInfo . Colors . Add ( new GradientStop ( Color . FromArgb ( 0 , 105 , 163 ) , 100f ) ) ;
2020-07-20 09:33:16 +12:00
break ;
case 1 :
2020-07-20 10:00:32 +12:00
gradientInfo . Colors . Add ( new GradientStop ( Color . FromArgb ( 255 , 3 , 135 ) , 0f ) ) ;
gradientInfo . Colors . Add ( new GradientStop ( Color . FromArgb ( 255 , 143 , 3 ) , 100f ) ) ;
2020-07-20 09:33:16 +12:00
break ;
case 2 :
2020-07-20 10:00:32 +12:00
gradientInfo . Colors . Add ( new GradientStop ( Color . FromArgb ( 184 , 11 , 195 ) , 0f ) ) ;
gradientInfo . Colors . Add ( new GradientStop ( Color . FromArgb ( 98 , 54 , 255 ) , 100f ) ) ;
2020-07-20 09:33:16 +12:00
break ;
}
2021-08-19 11:21:29 +12:00
return gradientInfo ;
2020-07-20 09:33:16 +12:00
}
public override Bitmap Apply ( Bitmap bmp )
{
if ( string . IsNullOrEmpty ( Text ) )
{
return bmp ;
}
using ( Font font = Font )
{
if ( font = = null | | font . Size < 1 )
{
return bmp ;
}
NameParser parser = new NameParser ( NameParserType . Text ) ;
parser . ImageWidth = bmp . Width ;
parser . ImageHeight = bmp . Height ;
string parsedText = parser . Parse ( Text ) ;
using ( Graphics g = Graphics . FromImage ( bmp ) )
using ( GraphicsPath gp = new GraphicsPath ( ) )
{
2020-07-21 05:03:49 +12:00
g . SmoothingMode = SmoothingMode . HighQuality ;
g . PixelOffsetMode = PixelOffsetMode . Half ;
2020-07-20 09:33:16 +12:00
gp . FillMode = FillMode . Winding ;
float emSize = g . DpiY * font . SizeInPoints / 72 ;
gp . AddString ( parsedText , font . FontFamily , ( int ) font . Style , emSize , Point . Empty , StringFormat . GenericDefault ) ;
2020-07-21 05:03:49 +12:00
if ( Angle ! = 0 )
{
using ( Matrix matrix = new Matrix ( ) )
{
matrix . Rotate ( Angle ) ;
gp . Transform ( matrix ) ;
}
}
2020-07-20 09:33:16 +12:00
RectangleF pathRect = gp . GetBounds ( ) ;
if ( pathRect . IsEmpty )
{
return bmp ;
}
2020-07-29 01:52:31 +12:00
Size textSize = pathRect . Size . ToSize ( ) . Offset ( 1 ) ;
2020-07-20 09:33:16 +12:00
Point textPosition = Helpers . GetPosition ( Placement , Offset , bmp . Size , textSize ) ;
Rectangle textRectangle = new Rectangle ( textPosition , textSize ) ;
if ( AutoHide & & ! new Rectangle ( 0 , 0 , bmp . Width , bmp . Height ) . Contains ( textRectangle ) )
{
return bmp ;
}
using ( Matrix matrix = new Matrix ( ) )
{
matrix . Translate ( textRectangle . X - pathRect . X , textRectangle . Y - pathRect . Y ) ;
gp . Transform ( matrix ) ;
}
2020-07-20 10:24:07 +12:00
// Draw text shadow
2020-07-21 05:19:51 +12:00
if ( Shadow & & ( ( ! ShadowUseGradient & & ShadowColor . A > 0 ) | | ( ShadowUseGradient & & ShadowGradient . IsVisible ) ) )
2020-07-20 10:24:07 +12:00
{
using ( Matrix matrix = new Matrix ( ) )
{
2020-07-21 05:19:51 +12:00
matrix . Translate ( ShadowOffset . X , ShadowOffset . Y ) ;
2020-07-20 10:24:07 +12:00
gp . Transform ( matrix ) ;
2020-07-21 05:19:51 +12:00
if ( Outline & & OutlineSize > 0 )
2020-07-20 10:24:07 +12:00
{
2020-07-21 05:19:51 +12:00
if ( ShadowUseGradient )
2020-07-20 16:00:43 +12:00
{
2020-07-21 05:19:51 +12:00
using ( LinearGradientBrush textShadowBrush = ShadowGradient . GetGradientBrush (
Rectangle . Round ( textRectangle ) . Offset ( OutlineSize + 1 ) . LocationOffset ( ShadowOffset ) ) )
using ( Pen textShadowPen = new Pen ( textShadowBrush , OutlineSize ) { LineJoin = LineJoin . Round } )
2020-07-20 16:00:43 +12:00
{
g . DrawPath ( textShadowPen , gp ) ;
}
}
else
2020-07-20 10:24:07 +12:00
{
2020-07-21 05:19:51 +12:00
using ( Pen textShadowPen = new Pen ( ShadowColor , OutlineSize ) { LineJoin = LineJoin . Round } )
2020-07-20 16:00:43 +12:00
{
g . DrawPath ( textShadowPen , gp ) ;
}
2020-07-20 10:24:07 +12:00
}
}
else
{
2020-07-21 05:19:51 +12:00
if ( ShadowUseGradient )
2020-07-20 16:00:43 +12:00
{
2020-07-21 05:19:51 +12:00
using ( Brush textShadowBrush = ShadowGradient . GetGradientBrush (
Rectangle . Round ( textRectangle ) . Offset ( 1 ) . LocationOffset ( ShadowOffset ) ) )
2020-07-20 16:00:43 +12:00
{
g . FillPath ( textShadowBrush , gp ) ;
}
}
else
2020-07-20 10:24:07 +12:00
{
2020-07-21 05:19:51 +12:00
using ( Brush textShadowBrush = new SolidBrush ( ShadowColor ) )
2020-07-20 16:00:43 +12:00
{
g . FillPath ( textShadowBrush , gp ) ;
}
2020-07-20 10:24:07 +12:00
}
}
matrix . Reset ( ) ;
2020-07-21 05:19:51 +12:00
matrix . Translate ( - ShadowOffset . X , - ShadowOffset . Y ) ;
2020-07-20 10:24:07 +12:00
gp . Transform ( matrix ) ;
}
}
2020-07-20 10:00:32 +12:00
// Draw text outline
2020-07-21 05:19:51 +12:00
if ( Outline & & OutlineSize > 0 )
2020-07-20 09:33:16 +12:00
{
2020-07-21 05:19:51 +12:00
if ( OutlineUseGradient )
2020-07-20 09:33:16 +12:00
{
2020-07-21 05:19:51 +12:00
if ( OutlineGradient . IsVisible )
2020-07-20 10:00:32 +12:00
{
2020-07-21 05:19:51 +12:00
using ( LinearGradientBrush textOutlineBrush = OutlineGradient . GetGradientBrush ( Rectangle . Round ( textRectangle ) . Offset ( OutlineSize + 1 ) ) )
using ( Pen textOutlinePen = new Pen ( textOutlineBrush , OutlineSize ) { LineJoin = LineJoin . Round } )
2020-07-20 15:25:38 +12:00
{
g . DrawPath ( textOutlinePen , gp ) ;
}
2020-07-20 10:00:32 +12:00
}
2020-07-20 09:33:16 +12:00
}
2020-07-21 05:19:51 +12:00
else if ( OutlineColor . A > 0 )
2020-07-20 09:33:16 +12:00
{
2020-07-21 05:19:51 +12:00
using ( Pen textOutlinePen = new Pen ( OutlineColor , OutlineSize ) { LineJoin = LineJoin . Round } )
2020-07-20 10:00:32 +12:00
{
g . DrawPath ( textOutlinePen , gp ) ;
}
2020-07-20 09:33:16 +12:00
}
2020-07-20 10:00:32 +12:00
}
2020-07-20 09:33:16 +12:00
2020-07-20 10:00:32 +12:00
// Draw text
2020-07-21 05:19:51 +12:00
if ( UseGradient )
2020-07-20 10:00:32 +12:00
{
2020-07-21 05:19:51 +12:00
if ( Gradient . IsVisible )
2020-07-20 10:00:32 +12:00
{
2020-07-21 05:19:51 +12:00
using ( Brush textBrush = Gradient . GetGradientBrush ( Rectangle . Round ( textRectangle ) . Offset ( 1 ) ) )
2020-07-20 15:25:38 +12:00
{
g . FillPath ( textBrush , gp ) ;
}
2020-07-20 10:00:32 +12:00
}
2020-07-20 09:33:16 +12:00
}
2020-07-21 05:19:51 +12:00
else if ( Color . A > 0 )
2020-07-20 09:33:16 +12:00
{
2020-07-21 05:19:51 +12:00
using ( Brush textBrush = new SolidBrush ( Color ) )
2020-07-20 10:00:32 +12:00
{
g . FillPath ( textBrush , gp ) ;
}
2020-07-20 09:33:16 +12:00
}
}
return bmp ;
}
}
}
}