├── .gitattributes ├── .gitignore ├── Binary ├── BumpKit.dll └── Bumpkit.1.0.2.nupkg ├── BumpKit ├── BumpKit.sln ├── BumpKit │ ├── BumpKit.csproj │ ├── ColorExtensions.cs │ ├── FontEffects.cs │ ├── GifEncoder.cs │ ├── ImageExtensions.cs │ ├── PointExtensions.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ScalingMode.cs │ └── UnsafeBitmapContext.cs └── Demonstrations │ ├── Demonstrations.csproj │ ├── Form1.Designer.cs │ ├── Form1.cs │ ├── Form1.resx │ ├── Program.cs │ └── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /Binary/BumpKit.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataDink/Bumpkit/c20d49a67c6c7c72a1cc5c77771b3210cfe670e4/Binary/BumpKit.dll -------------------------------------------------------------------------------- /Binary/Bumpkit.1.0.2.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataDink/Bumpkit/c20d49a67c6c7c72a1cc5c77771b3210cfe670e4/Binary/Bumpkit.1.0.2.nupkg -------------------------------------------------------------------------------- /BumpKit/BumpKit.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BumpKit", "BumpKit\BumpKit.csproj", "{E6D966F2-B1A1-4EE1-911F-DD798DE6C593}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demonstrations", "Demonstrations\Demonstrations.csproj", "{17809A48-1B3F-4F43-9391-C9BDE0380293}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|Mixed Platforms = Debug|Mixed Platforms 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|Mixed Platforms = Release|Mixed Platforms 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 21 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 22 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Debug|x86.ActiveCfg = Debug|Any CPU 23 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 26 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Release|Mixed Platforms.Build.0 = Release|Any CPU 27 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593}.Release|x86.ActiveCfg = Release|Any CPU 28 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Debug|Any CPU.ActiveCfg = Debug|x86 29 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 30 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Debug|Mixed Platforms.Build.0 = Debug|x86 31 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Debug|x86.ActiveCfg = Debug|x86 32 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Debug|x86.Build.0 = Debug|x86 33 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Release|Any CPU.ActiveCfg = Release|x86 34 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Release|Mixed Platforms.ActiveCfg = Release|x86 35 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Release|Mixed Platforms.Build.0 = Release|x86 36 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Release|x86.ActiveCfg = Release|x86 37 | {17809A48-1B3F-4F43-9391-C9BDE0380293}.Release|x86.Build.0 = Release|x86 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/BumpKit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593} 9 | Library 10 | Properties 11 | BumpKit 12 | BumpKit 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | true 25 | 26 | 27 | none 28 | true 29 | bin\Release\ 30 | 31 | 32 | prompt 33 | 4 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/ColorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace BumpKit 5 | { 6 | public static class ColorExtensions 7 | { 8 | /// 9 | /// Compares a pixel and color and determines equality. 10 | /// 11 | public static bool EqualsColor(this UnsafeBitmapContext.Pixel pixel, Color color) 12 | { 13 | return (color.A == 0 && pixel.Alpha == 0) 14 | || (color.A == pixel.Alpha && color.R == pixel.Red && color.G == pixel.Green && color.B == pixel.Blue); 15 | } 16 | 17 | /// 18 | /// Compares a pixel and color and determines equality. 19 | /// 20 | public static bool EqualsPixel(this Color color, UnsafeBitmapContext.Pixel pixel) 21 | { 22 | return pixel.EqualsColor(color); 23 | } 24 | 25 | /// 26 | /// Creates a fade to a target color by percentage 27 | /// 28 | /// The source color 29 | /// The target color 30 | /// The amount of the fade from 0 to 1 31 | /// 32 | public static Color FadeTo(this Color from, Color to, float fade) 33 | { 34 | return Color.FromArgb((int) Math.Min(255, Math.Max(0, from.A + (to.A - from.A)*fade)), 35 | (int) Math.Min(255, Math.Max(0, from.R + (to.R - from.R)*fade)), 36 | (int) Math.Min(255, Math.Max(0, from.G + (to.G - from.G)*fade)), 37 | (int) Math.Min(255, Math.Max(0, from.B + (to.B - from.B)*fade))); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/FontEffects.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Linq; 6 | 7 | namespace BumpKit 8 | { 9 | public static class FontEffects 10 | { 11 | /// 12 | /// Measures a string's pixel boundaries (without the extra padding MeasureString gives).
13 | /// NOTE: This bench tests just under 50% slower than MeasureString. 14 | ///
15 | /// The source graphics object 16 | /// The text to measure 17 | /// The font to measure 18 | /// 19 | public static RectangleF MeasureStringBoundaries(this Graphics gfx, string text, Font font) 20 | { 21 | var rect = new RectangleF(0, 0, int.MaxValue, int.MaxValue); 22 | var format = new StringFormat(); 23 | format.SetMeasurableCharacterRanges(new[] { new CharacterRange(0, text.Length) }); 24 | var regions = gfx.MeasureCharacterRanges(text, font, rect, format); 25 | return regions[0].GetBounds(gfx); 26 | } 27 | 28 | /// 29 | /// Measures a string's pixel boundaries including border width (without the extra padding MeasureString gives).
30 | /// NOTE: This bench tests just under 50% slower than MeasureString. 31 | ///
32 | /// The source graphics object 33 | /// The text to measure 34 | /// The font to measure 35 | /// The intended border width 36 | /// 37 | public static RectangleF MeasureStringBoundaries(this Graphics gfx, string text, Font font, int border) 38 | { 39 | const float pathOffset = (float)0.97389271333939476; 40 | var measure = MeasureStringBoundaries(gfx, text, font); 41 | return new RectangleF(0, 0, (measure.Width/pathOffset + border*2)/pathOffset, measure.Height + border*2); 42 | } 43 | 44 | /// 45 | /// Draws text with a border. 46 | /// 47 | /// The source graphics object 48 | /// The text to render 49 | /// The font to render 50 | /// The brush to use for the rendered text 51 | /// The x location to render the text at 52 | /// The y location to render the text at 53 | /// The width of the border to render in pixels 54 | /// A collection of colors to border should cycle through 55 | /// An index-matching collection of offsets to render the border colors at 56 | public static void DrawString(this Graphics gfx, string text, Font font, Brush brush, int x, int y, int border, Color[] borderColors, float[] colorOffsets) 57 | { 58 | if (string.IsNullOrWhiteSpace(text)) 59 | return; 60 | if (gfx == null) 61 | throw new ArgumentNullException("gfx"); 62 | if (font == null) 63 | throw new ArgumentNullException("font"); 64 | if (brush == null) 65 | throw new ArgumentNullException("brush"); 66 | if (border <= 0) 67 | throw new ArgumentException("Border must be greater than 0", "border"); 68 | if (borderColors.Length == 0) 69 | throw new ArgumentException("Border requires at least 1 color", "borderColors"); 70 | if (borderColors.Length > 1 && borderColors.Length != colorOffsets.Length) 71 | throw new ArgumentException("A border with more than 1 color requires a matching number of offsets", "colorOffsets"); 72 | if (colorOffsets == null || colorOffsets.Length == 0) 73 | colorOffsets = new[] {(float)0}; 74 | 75 | // Organize color fades from inner to outer 76 | var colors = borderColors 77 | .Select((c, i) => new KeyValuePair(colorOffsets[i], c)) 78 | .OrderBy(c => c.Key) 79 | .ToArray(); 80 | // Get bordered boundaries 81 | var offset = gfx.MeasureStringBoundaries(text, font).Location; 82 | var measure = gfx.MeasureStringBoundaries(text, font, border); 83 | 84 | using (var workImage = new Bitmap((int)measure.Width, (int)measure.Height)) 85 | using (var gfxWork = Graphics.FromImage(workImage)) 86 | { 87 | gfxWork.PageUnit = GraphicsUnit.Point; 88 | gfxWork.SmoothingMode = gfx.SmoothingMode; 89 | var path = new GraphicsPath(); 90 | path.AddString(text, font.FontFamily, (int) font.Style, font.Size, new PointF((border-offset.X)*(float).75, (border-offset.Y)*(float).75), StringFormat.GenericDefault); 91 | 92 | // Fade the border from outer to inner. 93 | for (var b = border; b > 0; b--) 94 | { 95 | var colorIndex = (float) 1/border*b; 96 | var colorStart = colors.Length > 1 ? colors.Last(c => c.Key <= colorIndex) : colors.First(); 97 | var colorEnd = colors.Length > 1 ? colors.First(c => c.Key >= colorIndex) : colors.First(); 98 | var colorOffset = 1/Math.Max((float).0000001, colorEnd.Key - colorStart.Key)*(colorIndex - colorStart.Key); 99 | var color = colorStart.Value.FadeTo(colorEnd.Value, colorOffset); 100 | 101 | const float lineWidthOffset = (float) .65; // This is approximate 102 | using (var pen = new Pen(color, b/lineWidthOffset) { LineJoin = LineJoin.Round }) 103 | gfxWork.DrawPath(pen, path); 104 | } 105 | 106 | // Draw the text 107 | gfxWork.FillPath(brush, path); 108 | var bounds = workImage.DetectPadding(); 109 | var offsetX = ((measure.Width - bounds.Right) - bounds.X)/2; 110 | 111 | // Apply the generated image 112 | gfx.DrawImage(workImage, x + offsetX, y); 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/GifEncoder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.IO; 5 | using System.Linq; 6 | 7 | namespace BumpKit 8 | { 9 | /// 10 | /// Encodes multiple images as an animated gif to a stream.
11 | /// ALWAYS ALWAYS ALWAYS wire this up in a using block
12 | /// Disposing the encoder will complete the file.
13 | /// Uses default .net GIF encoding and adds animation headers. 14 | ///
15 | public class GifEncoder : IDisposable 16 | { 17 | #region Header Constants 18 | private const string FileType = "GIF"; 19 | private const string FileVersion = "89a"; 20 | private const byte FileTrailer = 0x3b; 21 | 22 | private const int ApplicationExtensionBlockIdentifier = 0xff21; 23 | private const byte ApplicationBlockSize = 0x0b; 24 | private const string ApplicationIdentification = "NETSCAPE2.0"; 25 | 26 | private const int GraphicControlExtensionBlockIdentifier = 0xf921; 27 | private const byte GraphicControlExtensionBlockSize = 0x04; 28 | 29 | private const long SourceGlobalColorInfoPosition = 10; 30 | private const long SourceGraphicControlExtensionPosition = 781; 31 | private const long SourceGraphicControlExtensionLength = 8; 32 | private const long SourceImageBlockPosition = 789; 33 | private const long SourceImageBlockHeaderLength = 11; 34 | private const long SourceColorBlockPosition = 13; 35 | private const long SourceColorBlockLength = 768; 36 | #endregion 37 | 38 | private bool _isFirstImage = true; 39 | private int? _width; 40 | private int? _height; 41 | private int? _repeatCount; 42 | private readonly Stream _stream; 43 | 44 | // Public Accessors 45 | public TimeSpan FrameDelay { get; set; } 46 | 47 | /// 48 | /// Encodes multiple images as an animated gif to a stream.
49 | /// ALWAYS ALWAYS ALWAYS wire this in a using block
50 | /// Disposing the encoder will complete the file.
51 | /// Uses default .net GIF encoding and adds animation headers. 52 | ///
53 | /// The stream that will be written to. 54 | /// Sets the width for this gif or null to use the first frame's width. 55 | /// Sets the height for this gif or null to use the first frame's height. 56 | public GifEncoder(Stream stream, int? width = null, int? height = null, int? repeatCount = null) 57 | { 58 | _stream = stream; 59 | _width = width; 60 | _height = height; 61 | _repeatCount = repeatCount; 62 | } 63 | 64 | /// 65 | /// Adds a frame to this animation. 66 | /// 67 | /// The image to add 68 | /// The positioning x offset this image should be displayed at. 69 | /// The positioning y offset this image should be displayed at. 70 | public void AddFrame(Image img, int x = 0, int y = 0, TimeSpan? frameDelay = null) 71 | { 72 | using (var gifStream = new MemoryStream()) 73 | { 74 | img.Save(gifStream, ImageFormat.Gif); 75 | if (_isFirstImage) // Steal the global color table info 76 | { 77 | InitHeader(gifStream, img.Width, img.Height); 78 | } 79 | WriteGraphicControlBlock(gifStream, frameDelay.GetValueOrDefault(FrameDelay)); 80 | WriteImageBlock(gifStream, !_isFirstImage, x, y, img.Width, img.Height); 81 | } 82 | _isFirstImage = false; 83 | } 84 | 85 | private void InitHeader(Stream sourceGif, int w, int h) 86 | { 87 | // File Header 88 | WriteString(FileType); 89 | WriteString(FileVersion); 90 | WriteShort(_width.GetValueOrDefault(w)); // Initial Logical Width 91 | WriteShort(_height.GetValueOrDefault(h)); // Initial Logical Height 92 | sourceGif.Position = SourceGlobalColorInfoPosition; 93 | WriteByte(sourceGif.ReadByte()); // Global Color Table Info 94 | WriteByte(0); // Background Color Index 95 | WriteByte(0); // Pixel aspect ratio 96 | WriteColorTable(sourceGif); 97 | 98 | // App Extension Header 99 | WriteShort(ApplicationExtensionBlockIdentifier); 100 | WriteByte(ApplicationBlockSize); 101 | WriteString(ApplicationIdentification); 102 | WriteByte(3); // Application block length 103 | WriteByte(1); 104 | WriteShort(_repeatCount.GetValueOrDefault(0)); // Repeat count for images. 105 | WriteByte(0); // terminator 106 | } 107 | 108 | private void WriteColorTable(Stream sourceGif) 109 | { 110 | sourceGif.Position = SourceColorBlockPosition; // Locating the image color table 111 | var colorTable = new byte[SourceColorBlockLength]; 112 | sourceGif.Read(colorTable, 0, colorTable.Length); 113 | _stream.Write(colorTable, 0, colorTable.Length); 114 | } 115 | 116 | private void WriteGraphicControlBlock(Stream sourceGif, TimeSpan frameDelay) 117 | { 118 | sourceGif.Position = SourceGraphicControlExtensionPosition; // Locating the source GCE 119 | var blockhead = new byte[SourceGraphicControlExtensionLength]; 120 | sourceGif.Read(blockhead, 0, blockhead.Length); // Reading source GCE 121 | 122 | WriteShort(GraphicControlExtensionBlockIdentifier); // Identifier 123 | WriteByte(GraphicControlExtensionBlockSize); // Block Size 124 | WriteByte(blockhead[3] & 0xf7 | 0x08); // Setting disposal flag 125 | WriteShort(Convert.ToInt32(frameDelay.TotalMilliseconds / 10)); // Setting frame delay 126 | WriteByte(blockhead[6]); // Transparent color index 127 | WriteByte(0); // Terminator 128 | } 129 | 130 | private void WriteImageBlock(Stream sourceGif, bool includeColorTable, int x, int y, int h, int w) 131 | { 132 | sourceGif.Position = SourceImageBlockPosition; // Locating the image block 133 | var header = new byte[SourceImageBlockHeaderLength]; 134 | sourceGif.Read(header, 0, header.Length); 135 | WriteByte(header[0]); // Separator 136 | WriteShort(x); // Position X 137 | WriteShort(y); // Position Y 138 | WriteShort(h); // Height 139 | WriteShort(w); // Width 140 | 141 | if (includeColorTable) // If first frame, use global color table - else use local 142 | { 143 | sourceGif.Position = SourceGlobalColorInfoPosition; 144 | WriteByte(sourceGif.ReadByte() & 0x3f | 0x80); // Enabling local color table 145 | WriteColorTable(sourceGif); 146 | } 147 | else 148 | { 149 | WriteByte(header[9] & 0x07 | 0x07); // Disabling local color table 150 | } 151 | 152 | WriteByte(header[10]); // LZW Min Code Size 153 | 154 | // Read/Write image data 155 | sourceGif.Position = SourceImageBlockPosition + SourceImageBlockHeaderLength; 156 | 157 | var dataLength = sourceGif.ReadByte(); 158 | while (dataLength > 0) 159 | { 160 | var imgData = new byte[dataLength]; 161 | sourceGif.Read(imgData, 0, dataLength); 162 | 163 | _stream.WriteByte(Convert.ToByte(dataLength)); 164 | _stream.Write(imgData, 0, dataLength); 165 | dataLength = sourceGif.ReadByte(); 166 | } 167 | 168 | _stream.WriteByte(0); // Terminator 169 | 170 | } 171 | 172 | private void WriteByte(int value) 173 | { 174 | _stream.WriteByte(Convert.ToByte(value)); 175 | } 176 | 177 | private void WriteShort(int value) 178 | { 179 | _stream.WriteByte(Convert.ToByte(value & 0xff)); 180 | _stream.WriteByte(Convert.ToByte((value >> 8) & 0xff)); 181 | } 182 | 183 | private void WriteString(string value) 184 | { 185 | _stream.Write(value.ToArray().Select(c => (byte)c).ToArray(), 0, value.Length); 186 | } 187 | 188 | public void Dispose() 189 | { 190 | // Complete File 191 | WriteByte(FileTrailer); 192 | 193 | // Pushing data 194 | _stream.Flush(); 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/ImageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Drawing2D; 4 | 5 | namespace BumpKit 6 | { 7 | public static class ImageExtensions 8 | { 9 | /// 10 | /// Provides quick but unsafe access to this image's pixels.
11 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
12 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
13 | ///
14 | public static UnsafeBitmapContext CreateUnsafeContext(this Image image) 15 | { 16 | return new UnsafeBitmapContext(image); 17 | } 18 | 19 | /// 20 | /// Detects the widest and tallest pixels to determine the image padding based on the optional background color. 21 | /// 22 | /// The original image 23 | /// Specifies a background color for this image or transparent by default. 24 | /// A rectangle containing the borders of this image's content. 25 | public static Rectangle DetectPadding(this Image image, Color backgroundColor = default(Color)) 26 | { 27 | if (backgroundColor.IsEmpty) 28 | backgroundColor = Color.Transparent; 29 | 30 | var top = image.Height; 31 | var bottom = 0; 32 | var left = image.Width; 33 | var right = 0; 34 | var width = image.Width - 1; 35 | var height = image.Height - 1; 36 | using (var context = new UnsafeBitmapContext(image)) 37 | { 38 | for (int y = 0; y < context.Height; y++) 39 | for (int x = 0; x < context.Width; x++) 40 | { 41 | if (width - right <= x && left <= x && height - bottom <= y) 42 | break; 43 | if (x < left && !context.GetRawPixel(x, y).EqualsColor(backgroundColor)) 44 | { 45 | if (y < top) { top = y; } 46 | left = x; 47 | } 48 | if (x < width - right && !context.GetRawPixel(width - x, y).EqualsColor(backgroundColor)) 49 | { 50 | if (y < top) { top = y; } 51 | right = width - x; 52 | } 53 | if (y < height - bottom && !context.GetRawPixel(x, height - y).EqualsColor(backgroundColor)) 54 | { 55 | bottom = height - y; 56 | } 57 | } 58 | } 59 | width = Math.Max(0, right - left); 60 | height = Math.Max(0, bottom - top); 61 | return new Rectangle(left, top, width, height); 62 | } 63 | 64 | /// 65 | /// Clones this image scaled to fit the specified size. 66 | /// 67 | /// The original image. 68 | /// The size to scale the clone to. 69 | /// FitToContent will scale the content to be completely contained in the specified size.
70 | /// Overflow will maximize the image to completely fill the specified size, clipping excess content. 71 | /// A clone of this image scaled to the specified size. 72 | public static Image ScaleToFit(this Image image, Size size, ScalingMode mode = ScalingMode.FitContent) 73 | { 74 | return image.ScaleToFit(size, default(Color), true, mode); 75 | } 76 | 77 | /// 78 | /// Clones this image scaled to fit the specified size. 79 | /// 80 | /// The original image. 81 | /// The size to scale the clone to. 82 | /// The color to fill unused image space with. 83 | /// FitToContent will scale the content to be completely contained in the specified size.
84 | /// Overflow will maximize the image to completely fill the specified size, clipping excess content. 85 | /// A clone of this image scaled to the specified size. 86 | public static Image ScaleToFit(this Image image, Size size, Color backgroundColor, ScalingMode mode = ScalingMode.FitContent) 87 | { 88 | return image.ScaleToFit(size, backgroundColor, true, mode); 89 | } 90 | 91 | /// 92 | /// Clones this image scaled to fit the specified size. 93 | /// 94 | /// The original image. 95 | /// The size to scale the clone to. 96 | /// If true, disposes this image upon cloning. 97 | /// FitToContent will scale the content to be completely contained in the specified size.
98 | /// Overflow will maximize the image to completely fill the specified size, clipping excess content. 99 | /// A clone of this image scaled to the specified size. 100 | public static Image ScaleToFit(this Image image, Size size, bool dispose, ScalingMode mode = ScalingMode.FitContent) 101 | { 102 | return image.ScaleToFit(size, default(Color), dispose, mode); 103 | } 104 | 105 | /// 106 | /// Clones this image scaled to fit the specified size. 107 | /// 108 | /// The original image. 109 | /// The size to scale the clone to. 110 | /// The color to fill unused image space with. 111 | /// If true, disposes this image upon cloning. 112 | /// FitToContent will scale the content to be completely contained in the specified size.
113 | /// Overflow will maximize the image to completely fill the specified size, clipping excess content. 114 | /// A clone of this image scaled to the specified size. 115 | public static Image ScaleToFit(this Image image, Size size, Color backgroundColor, bool dispose = true, ScalingMode mode = ScalingMode.FitContent) 116 | { 117 | var widthRatio = (double) size.Width/image.Width; 118 | var heightRatio = (double) size.Height/image.Height; 119 | var scaleRatio = mode == ScalingMode.Overflow 120 | ? Math.Max(widthRatio, heightRatio) 121 | : Math.Min(widthRatio, heightRatio); 122 | var width = image.Width*scaleRatio; 123 | var height = image.Height*scaleRatio; 124 | 125 | var newImage = new Bitmap(size.Width, size.Height); 126 | using (var gfx = Graphics.FromImage(newImage)) 127 | { 128 | if (!backgroundColor.IsEmpty) 129 | gfx.Clear(backgroundColor); 130 | gfx.DrawImage(image, 131 | (float)((newImage.Width - width) / 2), (float)((newImage.Height - height) / 2), 132 | (float)width, (float)height); 133 | } 134 | if (dispose) image.Dispose(); 135 | return newImage; 136 | } 137 | 138 | /// 139 | /// Clones this image stretched to the specified size. 140 | /// 141 | /// The original image. 142 | /// The size to stretch the clone to. 143 | /// If true, disposes this image upon cloning. 144 | /// A clone of this image streched to the specified size. 145 | public static Image Stretch(this Image image, Size size, bool dispose = true) 146 | { 147 | var newImage = new Bitmap(size.Width, size.Height); 148 | using (var gfx = Graphics.FromImage(newImage)) 149 | { 150 | gfx.DrawImage(image, 0, 0, size.Width, size.Height); 151 | } 152 | if (dispose) image.Dispose(); 153 | return newImage; 154 | } 155 | 156 | /// 157 | /// Clones this image with the specified rotation. 158 | /// 159 | /// The original image 160 | /// The angle to rotate the image 161 | /// FitToContent will resize the clone accordingly to fit the rotated content.
162 | /// Overflow will maintain the original size and clip content. 163 | /// A clone of this image with the specified rotation. 164 | public static Image Rotate(this Image image, double angle, ScalingMode mode = ScalingMode.Overflow) 165 | { 166 | return image.Rotate(angle, true, mode); 167 | } 168 | 169 | /// 170 | /// Clones this image with the specified rotation. 171 | /// 172 | /// The original image 173 | /// The angle to rotate the image 174 | /// If true, disposes this image upon cloning. 175 | /// FitToContent will resize the clone accordingly to fit the rotated content.
176 | /// Overflow will maintain the original size and clip content. 177 | /// A clone of this image with the specified rotation. 178 | public static Image Rotate(this Image image, double angle, bool dispose, ScalingMode mode = ScalingMode.Overflow) 179 | { 180 | var width = image.Width; 181 | var height = image.Height; 182 | if (mode == ScalingMode.FitContent) 183 | { 184 | var o = angle%180; 185 | var d = Math.Sqrt(Math.Pow(image.Width, 2) + Math.Pow(image.Height, 2)); 186 | var a = (Math.Atan((double) image.Height/image.Width)*180/Math.PI) + (o > 90 ? 180 - o : o); 187 | height = (int)(Math.Sin(a * Math.PI / 180) * d); 188 | a = (Math.Atan((double) -image.Height/image.Width)*180/Math.PI) + (o > 90 ? 180 - o : o); 189 | width = (int)(Math.Cos(a * Math.PI / 180) * d); 190 | } 191 | var newImage = new Bitmap(width, height); 192 | using (var gfx = Graphics.FromImage(newImage)) 193 | { 194 | gfx.TranslateTransform(-image.Width/(float)2, -image.Height/(float)2, MatrixOrder.Prepend); 195 | gfx.RotateTransform((float)angle, MatrixOrder.Append); 196 | gfx.TranslateTransform(newImage.Width/(float)2, newImage.Height/(float)2, MatrixOrder.Append); 197 | gfx.DrawImage(image, 0, 0); 198 | } 199 | if (dispose) image.Dispose(); 200 | return newImage; 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/PointExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace BumpKit 5 | { 6 | public static class PointExtensions 7 | { 8 | /// 9 | /// Converts to an integer based point 10 | /// 11 | public static Point ToPoint(this PointF pointF) 12 | { 13 | return new Point((int)pointF.X, (int)pointF.Y); 14 | } 15 | 16 | /// 17 | /// Plots a new point the given distance and direction from the current point. 18 | /// 19 | /// The originating point. 20 | /// The direction to plot 21 | /// The distance to plot 22 | /// The plotted point 23 | public static PointF Plot(this PointF origin, float angle, float distance) 24 | { 25 | var radians = Math.PI/180*angle; 26 | var xplot = Math.Cos(radians)*distance; 27 | var yplot = Math.Sin(radians)*distance; 28 | return new PointF(origin.X + (float)xplot, origin.Y + (float)yplot); 29 | } 30 | 31 | /// 32 | /// Returns the distance the current plot is from 0, 0 33 | /// 34 | /// The current plot 35 | /// The point's distance 36 | public static double GetDistance(this PointF plot) 37 | { 38 | return Math.Sqrt(Math.Pow(plot.X, 2) + Math.Pow(plot.Y, 2)); 39 | } 40 | 41 | /// 42 | /// Returns the angle the current plot is from 0, 0 43 | /// 44 | /// The current plot 45 | /// The point's angle 46 | public static double GetAngle(this PointF plot) 47 | { 48 | return Math.Atan(plot.Y/plot.X)*180/Math.PI; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("BumpKit")] 9 | [assembly: AssemblyDescription("https://github.com/DataDink/Bumpkit")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Mark Nelson")] 12 | [assembly: AssemblyProduct("BumpKit")] 13 | [assembly: AssemblyCopyright("Mark Nelson Copyright © 2012")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c047a861-7cfc-44e4-9400-9f2de764cc75")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/ScalingMode.cs: -------------------------------------------------------------------------------- 1 | namespace BumpKit 2 | { 3 | public enum ScalingMode 4 | { 5 | FitContent, 6 | Overflow 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /BumpKit/BumpKit/UnsafeBitmapContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.IO; 5 | 6 | namespace BumpKit 7 | { 8 | /// 9 | /// Provides quick but unsafe access to a bitmap's bits.
10 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
11 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
12 | ///
13 | public sealed unsafe class UnsafeBitmapContext : IDisposable 14 | { 15 | private Stream _originalStream; 16 | private Bitmap _bitmap; 17 | private BitmapData _lockData; 18 | private Byte* _ptrBase; 19 | private int _pixelWidth; 20 | 21 | public int Width { get; private set; } 22 | public int Height { get; private set; } 23 | 24 | /// 25 | /// Provides quick but unsafe access to a bitmap's bits.
26 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
27 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
28 | ///
29 | /// The bitmap to access 30 | public UnsafeBitmapContext(Bitmap bitmap) 31 | { 32 | _bitmap = bitmap; 33 | LockBits(); 34 | } 35 | 36 | /// 37 | /// Provides quick but unsafe access to a bitmap's bits.
38 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
39 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
40 | ///
41 | /// The bitmap to access 42 | public UnsafeBitmapContext(Image image) 43 | { 44 | if (!(image is Bitmap)) 45 | { 46 | throw new ArgumentException("Image must be convertable to a bitmap."); 47 | } 48 | _bitmap = (Bitmap) image; 49 | LockBits(); 50 | } 51 | 52 | /// 53 | /// Provides quick but unsafe access to a bitmap's bits.
54 | /// The stream will be updated upon disposal.
55 | /// ALWAYS ALWAYS ALWAYS wire this in a using block.
56 | /// DO NOT EVER access the bitmap directly while in this unsafe context.
57 | ///
58 | /// The stream to read and write to. 59 | public UnsafeBitmapContext(Stream stream) 60 | { 61 | try 62 | { 63 | _originalStream = stream; 64 | stream.Position = 0; 65 | _bitmap = (Bitmap)Image.FromStream(stream); 66 | } 67 | catch { throw new ArgumentException("Stream did not contain a valid image format."); } 68 | LockBits(); 69 | } 70 | 71 | private void LockBits() 72 | { 73 | Width = _bitmap.Width; 74 | Height = _bitmap.Height; 75 | _pixelWidth = sizeof (Pixel); 76 | _lockData = _bitmap.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 77 | _ptrBase = (Byte*)_lockData.Scan0.ToPointer(); 78 | } 79 | 80 | public void Dispose() 81 | { 82 | _bitmap.UnlockBits(_lockData); 83 | _lockData = null; 84 | if (_originalStream != null) 85 | { 86 | _originalStream.SetLength(0); 87 | _originalStream.Position = 0; 88 | _bitmap.Save(_originalStream, _bitmap.RawFormat); 89 | _bitmap.Dispose(); 90 | _originalStream.Position = 0; 91 | } 92 | _originalStream = null; 93 | _bitmap = null; 94 | } 95 | 96 | /// 97 | /// Access a pixel from the bitmap's memory (slower than GetRawPixel) 98 | /// 99 | public Color GetPixel(int x, int y) 100 | { 101 | var pixel = GetRawPixel(x, y); 102 | return Color.FromArgb(pixel.Alpha, pixel.Red, pixel.Green, pixel.Blue); 103 | } 104 | 105 | /// 106 | /// Access a pixel from the bitmap's memory (faster than GetPixel)
107 | ///
108 | public Pixel GetRawPixel(int x, int y) 109 | { 110 | return *Pointer(x, y); 111 | } 112 | 113 | /// 114 | /// Replace a pixel in the bitmap's memory (slower than by bytes) 115 | /// 116 | public void SetPixel(int x, int y, Color color) 117 | { 118 | SetPixel(x, y, color.A, color.R, color.G, color.B); 119 | } 120 | 121 | /// 122 | /// Replace a pixel in the bitmap's memory (faster than by Color) 123 | /// 124 | public void SetPixel(int x, int y, byte alpha, byte red, byte green, byte blue) 125 | { 126 | var pixel = Pointer(x, y); 127 | (*pixel).Alpha = alpha; 128 | (*pixel).Red = red; 129 | (*pixel).Green = green; 130 | (*pixel).Blue = blue; 131 | } 132 | 133 | private Pixel* Pointer(int x, int y) 134 | { 135 | if (x >= Width || x < 0 || y >= Height || y < 0) 136 | { 137 | Dispose(); 138 | throw new ArgumentException("The X and Y parameters must be within the scope of the image pixel ranges."); 139 | } 140 | return (Pixel*) (_ptrBase + y*_lockData.Stride + x*_pixelWidth); 141 | } 142 | 143 | /// 144 | /// Represents raw pixel data. 145 | /// 146 | public struct Pixel 147 | { 148 | public byte Blue; 149 | public byte Green; 150 | public byte Red; 151 | public byte Alpha; 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Demonstrations.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {17809A48-1B3F-4F43-9391-C9BDE0380293} 9 | WinExe 10 | Properties 11 | Demonstrations 12 | Demonstrations 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Form 51 | 52 | 53 | Form1.cs 54 | 55 | 56 | 57 | 58 | Form1.cs 59 | 60 | 61 | ResXFileCodeGenerator 62 | Resources.Designer.cs 63 | Designer 64 | 65 | 66 | True 67 | Resources.resx 68 | 69 | 70 | SettingsSingleFileGenerator 71 | Settings.Designer.cs 72 | 73 | 74 | True 75 | Settings.settings 76 | True 77 | 78 | 79 | 80 | 81 | {E6D966F2-B1A1-4EE1-911F-DD798DE6C593} 82 | BumpKit 83 | 84 | 85 | 86 | 93 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Demonstrations 2 | { 3 | partial class Demonstrations 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.button1 = new System.Windows.Forms.Button(); 32 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 33 | this._rotateOverflow = new System.Windows.Forms.Panel(); 34 | this.label5 = new System.Windows.Forms.Label(); 35 | this._rotateFit = new System.Windows.Forms.Panel(); 36 | this.label4 = new System.Windows.Forms.Label(); 37 | this._stretch = new System.Windows.Forms.Panel(); 38 | this.label3 = new System.Windows.Forms.Label(); 39 | this._scaleToOverflow = new System.Windows.Forms.Panel(); 40 | this.label2 = new System.Windows.Forms.Label(); 41 | this._scaleToFit = new System.Windows.Forms.Panel(); 42 | this.label1 = new System.Windows.Forms.Label(); 43 | this.groupBox2 = new System.Windows.Forms.GroupBox(); 44 | this._textGen = new System.Windows.Forms.Panel(); 45 | this.label6 = new System.Windows.Forms.Label(); 46 | this._gifGeneration = new System.Windows.Forms.PictureBox(); 47 | this.label8 = new System.Windows.Forms.Label(); 48 | this._edgeDetection = new System.Windows.Forms.Panel(); 49 | this.label9 = new System.Windows.Forms.Label(); 50 | this._pixelManipulation = new System.Windows.Forms.Panel(); 51 | this.label10 = new System.Windows.Forms.Label(); 52 | this.groupBox1.SuspendLayout(); 53 | this.groupBox2.SuspendLayout(); 54 | ((System.ComponentModel.ISupportInitialize)(this._gifGeneration)).BeginInit(); 55 | this.SuspendLayout(); 56 | // 57 | // button1 58 | // 59 | this.button1.Location = new System.Drawing.Point(12, 12); 60 | this.button1.Name = "button1"; 61 | this.button1.Size = new System.Drawing.Size(792, 23); 62 | this.button1.TabIndex = 0; 63 | this.button1.Text = "Run Demonstrations"; 64 | this.button1.UseVisualStyleBackColor = true; 65 | this.button1.Click += new System.EventHandler(this.button1_Click); 66 | // 67 | // groupBox1 68 | // 69 | this.groupBox1.Controls.Add(this._rotateOverflow); 70 | this.groupBox1.Controls.Add(this.label5); 71 | this.groupBox1.Controls.Add(this._rotateFit); 72 | this.groupBox1.Controls.Add(this.label4); 73 | this.groupBox1.Controls.Add(this._stretch); 74 | this.groupBox1.Controls.Add(this.label3); 75 | this.groupBox1.Controls.Add(this._scaleToOverflow); 76 | this.groupBox1.Controls.Add(this.label2); 77 | this.groupBox1.Controls.Add(this._scaleToFit); 78 | this.groupBox1.Controls.Add(this.label1); 79 | this.groupBox1.Location = new System.Drawing.Point(12, 41); 80 | this.groupBox1.Name = "groupBox1"; 81 | this.groupBox1.Size = new System.Drawing.Size(792, 148); 82 | this.groupBox1.TabIndex = 1; 83 | this.groupBox1.TabStop = false; 84 | this.groupBox1.Text = "Transform Demonstrations"; 85 | // 86 | // _rotateOverflow 87 | // 88 | this._rotateOverflow.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 89 | this._rotateOverflow.Location = new System.Drawing.Point(633, 19); 90 | this._rotateOverflow.Name = "_rotateOverflow"; 91 | this._rotateOverflow.Size = new System.Drawing.Size(150, 100); 92 | this._rotateOverflow.TabIndex = 9; 93 | // 94 | // label5 95 | // 96 | this.label5.Location = new System.Drawing.Point(630, 122); 97 | this.label5.Name = "label5"; 98 | this.label5.Size = new System.Drawing.Size(153, 23); 99 | this.label5.TabIndex = 8; 100 | this.label5.Text = "Rotate (overflow)"; 101 | this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 102 | // 103 | // _rotateFit 104 | // 105 | this._rotateFit.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 106 | this._rotateFit.Location = new System.Drawing.Point(477, 19); 107 | this._rotateFit.Name = "_rotateFit"; 108 | this._rotateFit.Size = new System.Drawing.Size(150, 100); 109 | this._rotateFit.TabIndex = 7; 110 | // 111 | // label4 112 | // 113 | this.label4.Location = new System.Drawing.Point(474, 122); 114 | this.label4.Name = "label4"; 115 | this.label4.Size = new System.Drawing.Size(153, 23); 116 | this.label4.TabIndex = 6; 117 | this.label4.Text = "Rotate (fit)"; 118 | this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 119 | // 120 | // _stretch 121 | // 122 | this._stretch.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 123 | this._stretch.Location = new System.Drawing.Point(321, 19); 124 | this._stretch.Name = "_stretch"; 125 | this._stretch.Size = new System.Drawing.Size(150, 100); 126 | this._stretch.TabIndex = 5; 127 | // 128 | // label3 129 | // 130 | this.label3.Location = new System.Drawing.Point(318, 122); 131 | this.label3.Name = "label3"; 132 | this.label3.Size = new System.Drawing.Size(153, 23); 133 | this.label3.TabIndex = 4; 134 | this.label3.Text = "Stretch"; 135 | this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 136 | // 137 | // _scaleToOverflow 138 | // 139 | this._scaleToOverflow.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 140 | this._scaleToOverflow.Location = new System.Drawing.Point(165, 19); 141 | this._scaleToOverflow.Name = "_scaleToOverflow"; 142 | this._scaleToOverflow.Size = new System.Drawing.Size(150, 100); 143 | this._scaleToOverflow.TabIndex = 3; 144 | // 145 | // label2 146 | // 147 | this.label2.Location = new System.Drawing.Point(162, 122); 148 | this.label2.Name = "label2"; 149 | this.label2.Size = new System.Drawing.Size(153, 23); 150 | this.label2.TabIndex = 2; 151 | this.label2.Text = "Scale To Fit (overflow)"; 152 | this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 153 | // 154 | // _scaleToFit 155 | // 156 | this._scaleToFit.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 157 | this._scaleToFit.Location = new System.Drawing.Point(9, 19); 158 | this._scaleToFit.Name = "_scaleToFit"; 159 | this._scaleToFit.Size = new System.Drawing.Size(150, 100); 160 | this._scaleToFit.TabIndex = 1; 161 | // 162 | // label1 163 | // 164 | this.label1.Location = new System.Drawing.Point(6, 122); 165 | this.label1.Name = "label1"; 166 | this.label1.Size = new System.Drawing.Size(153, 23); 167 | this.label1.TabIndex = 0; 168 | this.label1.Text = "Scale To Fit (fit)"; 169 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 170 | // 171 | // groupBox2 172 | // 173 | this.groupBox2.Controls.Add(this._textGen); 174 | this.groupBox2.Controls.Add(this.label6); 175 | this.groupBox2.Controls.Add(this._gifGeneration); 176 | this.groupBox2.Controls.Add(this.label8); 177 | this.groupBox2.Controls.Add(this._edgeDetection); 178 | this.groupBox2.Controls.Add(this.label9); 179 | this.groupBox2.Controls.Add(this._pixelManipulation); 180 | this.groupBox2.Controls.Add(this.label10); 181 | this.groupBox2.Location = new System.Drawing.Point(12, 195); 182 | this.groupBox2.Name = "groupBox2"; 183 | this.groupBox2.Size = new System.Drawing.Size(792, 148); 184 | this.groupBox2.TabIndex = 10; 185 | this.groupBox2.TabStop = false; 186 | this.groupBox2.Text = "Unsafe Context Demonstrations"; 187 | // 188 | // _textGen 189 | // 190 | this._textGen.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 191 | this._textGen.Location = new System.Drawing.Point(477, 19); 192 | this._textGen.Name = "_textGen"; 193 | this._textGen.Size = new System.Drawing.Size(150, 100); 194 | this._textGen.TabIndex = 7; 195 | // 196 | // label6 197 | // 198 | this.label6.Location = new System.Drawing.Point(474, 122); 199 | this.label6.Name = "label6"; 200 | this.label6.Size = new System.Drawing.Size(153, 23); 201 | this.label6.TabIndex = 6; 202 | this.label6.Text = "Text Effects (Borders)"; 203 | this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 204 | // 205 | // _gifGeneration 206 | // 207 | this._gifGeneration.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 208 | this._gifGeneration.Location = new System.Drawing.Point(321, 19); 209 | this._gifGeneration.Name = "_gifGeneration"; 210 | this._gifGeneration.Size = new System.Drawing.Size(150, 100); 211 | this._gifGeneration.TabIndex = 5; 212 | this._gifGeneration.TabStop = false; 213 | // 214 | // label8 215 | // 216 | this.label8.Location = new System.Drawing.Point(318, 122); 217 | this.label8.Name = "label8"; 218 | this.label8.Size = new System.Drawing.Size(153, 23); 219 | this.label8.TabIndex = 4; 220 | this.label8.Text = "Gif Generation (Animations)"; 221 | this.label8.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 222 | // 223 | // _edgeDetection 224 | // 225 | this._edgeDetection.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 226 | this._edgeDetection.Location = new System.Drawing.Point(165, 19); 227 | this._edgeDetection.Name = "_edgeDetection"; 228 | this._edgeDetection.Size = new System.Drawing.Size(150, 100); 229 | this._edgeDetection.TabIndex = 3; 230 | // 231 | // label9 232 | // 233 | this.label9.Location = new System.Drawing.Point(162, 122); 234 | this.label9.Name = "label9"; 235 | this.label9.Size = new System.Drawing.Size(153, 23); 236 | this.label9.TabIndex = 2; 237 | this.label9.Text = "Edge Detection"; 238 | this.label9.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 239 | // 240 | // _pixelManipulation 241 | // 242 | this._pixelManipulation.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 243 | this._pixelManipulation.Location = new System.Drawing.Point(9, 19); 244 | this._pixelManipulation.Name = "_pixelManipulation"; 245 | this._pixelManipulation.Size = new System.Drawing.Size(150, 100); 246 | this._pixelManipulation.TabIndex = 1; 247 | // 248 | // label10 249 | // 250 | this.label10.Location = new System.Drawing.Point(6, 122); 251 | this.label10.Name = "label10"; 252 | this.label10.Size = new System.Drawing.Size(153, 23); 253 | this.label10.TabIndex = 0; 254 | this.label10.Text = "Fast Pixel Manipulation"; 255 | this.label10.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 256 | // 257 | // Demonstrations 258 | // 259 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 260 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 261 | this.ClientSize = new System.Drawing.Size(816, 354); 262 | this.Controls.Add(this.groupBox2); 263 | this.Controls.Add(this.groupBox1); 264 | this.Controls.Add(this.button1); 265 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 266 | this.MaximizeBox = false; 267 | this.MinimizeBox = false; 268 | this.Name = "Demonstrations"; 269 | this.Text = "Demonstrations"; 270 | this.groupBox1.ResumeLayout(false); 271 | this.groupBox2.ResumeLayout(false); 272 | ((System.ComponentModel.ISupportInitialize)(this._gifGeneration)).EndInit(); 273 | this.ResumeLayout(false); 274 | 275 | } 276 | 277 | #endregion 278 | 279 | private System.Windows.Forms.Button button1; 280 | private System.Windows.Forms.GroupBox groupBox1; 281 | private System.Windows.Forms.Panel _scaleToFit; 282 | private System.Windows.Forms.Label label1; 283 | private System.Windows.Forms.Panel _scaleToOverflow; 284 | private System.Windows.Forms.Label label2; 285 | private System.Windows.Forms.Panel _rotateOverflow; 286 | private System.Windows.Forms.Label label5; 287 | private System.Windows.Forms.Panel _rotateFit; 288 | private System.Windows.Forms.Label label4; 289 | private System.Windows.Forms.Panel _stretch; 290 | private System.Windows.Forms.Label label3; 291 | private System.Windows.Forms.GroupBox groupBox2; 292 | private System.Windows.Forms.PictureBox _gifGeneration; 293 | private System.Windows.Forms.Label label8; 294 | private System.Windows.Forms.Panel _edgeDetection; 295 | private System.Windows.Forms.Label label9; 296 | private System.Windows.Forms.Panel _pixelManipulation; 297 | private System.Windows.Forms.Label label10; 298 | private System.Windows.Forms.Label label6; 299 | private System.Windows.Forms.Panel _textGen; 300 | } 301 | } 302 | 303 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Drawing.Imaging; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Windows.Forms; 11 | using BumpKit; 12 | 13 | namespace Demonstrations 14 | { 15 | public partial class Demonstrations : Form 16 | { 17 | public Demonstrations() 18 | { 19 | InitializeComponent(); 20 | } 21 | 22 | private void button1_Click(object sender, EventArgs e) 23 | { 24 | var dlg = new OpenFileDialog { Title = "Please select an image to open:", Filter = "Jpeg|*.jpg|Jpeg|*.jpeg|Png|*.png|Bitmap|*.bmp" }; 25 | if (dlg.ShowDialog() != DialogResult.OK) 26 | return; 27 | 28 | var img = Image.FromFile(dlg.FileName); 29 | 30 | // Scale to fit 31 | _scaleToFit.BackgroundImage = img.ScaleToFit(_scaleToFit.Size, false); 32 | 33 | // Scale to fit (overflow) 34 | _scaleToOverflow.BackgroundImage = img.ScaleToFit(_scaleToOverflow.Size, false, ScalingMode.Overflow); 35 | 36 | // Stretch to fit 37 | _stretch.BackgroundImage = img.Stretch(_stretch.Size, false); 38 | 39 | // Rotate and fit 40 | _rotateFit.BackgroundImage = img.ScaleToFit(_rotateFit.Size, false).Rotate(45, ScalingMode.FitContent).ScaleToFit(_rotateOverflow.Size); 41 | 42 | // Rotate and overflow 43 | _rotateOverflow.BackgroundImage = img.ScaleToFit(_rotateOverflow.Size, false).Rotate(45); 44 | 45 | // Fast pixel manipulation (UnsafeContext) 46 | _pixelManipulation.BackgroundImage = img.ScaleToFit(_pixelManipulation.Size, false); 47 | using (var context = _pixelManipulation.BackgroundImage.CreateUnsafeContext()) 48 | { 49 | for (var y = 0; y < context.Height; y++) 50 | for (var x = 0; x < context.Width; x++) 51 | { 52 | var pixel = context.GetRawPixel(x, y); 53 | var level = Math.Max(pixel.Red, Math.Max(pixel.Green, pixel.Blue)); 54 | context.SetPixel(x, y, pixel.Alpha, level, level, level); 55 | } 56 | } 57 | _pixelManipulation.Refresh(); 58 | 59 | // Detect Edges 60 | var edge = new Bitmap(_edgeDetection.Width, _edgeDetection.Height); 61 | using (var gfx = Graphics.FromImage(edge)) 62 | { 63 | gfx.DrawEllipse(Pens.Black, 25, 25, 50, 50); 64 | var bounds = edge.DetectPadding(); 65 | gfx.DrawLine(Pens.Red, bounds.Left, 0, bounds.Left, edge.Height); 66 | gfx.DrawLine(Pens.Red, bounds.Right, 0, bounds.Right, edge.Height); 67 | gfx.DrawLine(Pens.Red, 0, bounds.Top, edge.Width, bounds.Top); 68 | gfx.DrawLine(Pens.Red, 0, bounds.Bottom, edge.Width, bounds.Bottom); 69 | } 70 | _edgeDetection.BackgroundImage = edge; 71 | 72 | // Create animated Gif 73 | var gifImage = img.ScaleToFit(_gifGeneration.Size, false); 74 | var gifStream = new MemoryStream(); // NOTE: Disposing this stream will break this demo - I don't know why. 75 | using (var encoder = new GifEncoder(gifStream)) 76 | for (var angle = 0; angle < 360; angle += 10) 77 | using (var frame = gifImage.Rotate(angle, false)) 78 | { 79 | encoder.AddFrame(frame, 0, 0, TimeSpan.FromSeconds(0)); 80 | } 81 | gifStream.Position = 0; 82 | _gifGeneration.Image = Image.FromStream(gifStream); 83 | 84 | // Draw text with effects 85 | _textGen.BackgroundImage = img.ScaleToFit(_textGen.Size, false, ScalingMode.Overflow); 86 | using (var gfx = Graphics.FromImage(_textGen.BackgroundImage)) 87 | { 88 | gfx.DrawString("A B C 1 2 3", new Font(FontFamily.Families.First(f => f.Name.Contains("Times")), 15), Brushes.Green, 15, 25, 10, 89 | new[] {Color.Yellow, Color.Blue, Color.Red, Color.Green, Color.Purple, Color.Black}, 90 | new[] { 0, (float).20, (float).40, (float).60, (float).80, 1 }); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Form1.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Drawing; 5 | using System.Drawing.Drawing2D; 6 | using System.Drawing.Text; 7 | using System.Linq; 8 | using System.Windows.Forms; 9 | using BumpKit; 10 | 11 | namespace Demonstrations 12 | { 13 | static class Program 14 | { 15 | /// 16 | /// The main entry point for the application. 17 | /// 18 | [STAThread] 19 | static void Main() 20 | { 21 | Application.EnableVisualStyles(); 22 | Application.SetCompatibleTextRenderingDefault(false); 23 | Application.Run(new Demonstrations()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Demonstrations")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Demonstrations")] 13 | [assembly: AssemblyCopyright("Copyright © 2012")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("07d392f9-a399-46cf-878d-4139b72609bf")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.239 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Demonstrations.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Demonstrations.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.239 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Demonstrations.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /BumpKit/Demonstrations/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bumpkit (1.0.1 Documentation) 2 | ============================= 3 | 4 | This is a .NET library that extends the System.Drawing GDI libraries. 5 | Useful for on-the-fly image generation in .NET-based web applications. 6 | 7 | Features: 8 | --------- 9 | * Image sizing/scaling extensions 10 | * Image rotation extensions 11 | * Lightning-fast pixel manipulation 12 | * Animated GIF generation (utilizes native gif encoding) 13 | * Font bordering and glow effects (DrawString on steroids) 14 | * Other extensions (Point, Color, etc) 15 | 16 | Scaling: 17 | -------- 18 | `System.Drawing.Image.ScaleToFit(...)` 19 | * Resize images with a single extension method 20 | * Maintain image aspect ratio sizing to a height or width or confine to a boundary 21 | 22 | Rotation: 23 | --------- 24 | `System.Drawing.Image.Rotate(...)` 25 | * Rotate images with a single extension method 26 | * Maintain image centering to boundaries and scale to fit or maintain sizing ratio 27 | 28 | Fast Pixel Access: 29 | ------------------ 30 | `System.Drawing.Image.CreateUnsafeContext()` 31 | * Provides access to an Image's pixels in a locked session 32 | * Allows lightning-fast custom image manipulation 33 | * Provides direct memory access wrapped in a light-weight disposable context 34 | 35 | Animated GIF Generation: 36 | ------------------------ 37 | `BumpKit.GifEncoder` 38 | * Formats multiple images/frames into a single animated GIF file 39 | * Utilizes native .NET GIF encoding (simply adds missing animation file-headers) 40 | * Fast (relative to other GIF libraries) 41 | 42 | Font Effects: 43 | ------------- 44 | `System.Drawing.Graphics.DrawString(text, font, brush, x, y, border, borderColors, colorOffsets)` 45 | * Utilizes native .NET font processing 46 | * Fast effect generation 47 | * Flexible API implementation 48 | 49 | Samples: 50 | -------- 51 | **Scaling an image to fit a specified size maintaining scale ratio** 52 |
var scaledImage = Image.FromFile("").ScaleToFit(new Size(100, 100));
53 | 54 | **Scaling an image to "overflow" or "cover" a specified size maintaining scale ratio** 55 |
var scaledImage = Image.FromFile("").ScaleToFit(new Size(100, 100), ScalingMode.Overflow);
56 | 57 | **Scaling an image without disposing the original image** 58 |
var img = Image.FromFile("");
 59 | var scaledImage = img.ScaleToFit(new Size(100, 100), false);
 60 | var scaledImage2 = img.ScaleToFit(new Size(100, 100), false, ScalingMode.Overflow);
61 | 62 | **Stretching an image to fit a specified size** 63 |
var stretchedImage = Image.FromFile("").Stretch(new Size(100, 100));
64 | 65 | **Rotating an image** 66 |
var rotationOverflow = Image.FromFile("").Rotate(45);
 67 | var rotationFit = Image.FromFile("").Rotate(45, ScalingMode.FitContent); // scales down to fit corner content
68 | 69 | **Detecting Image Edges (finding the crop points)** 70 |
var pixelBoundary = Image.FromFile("").DetectPadding(); // you can also specify the background color if it is not transparent
71 | 72 | **Direct Memory Access (reading/writing pixels quickly)** 73 |
// NOTE: This locks and accesses the bitmap's unmanaged memory. This is NOT thread-safe.
 74 | var image = Image.FromFile("");
 75 | using (var context = image.CreateUnsafeContext())
 76 | {
 77 | 	for (var x = 0; x < context.Width; x++)
 78 | 		for (var y = 0; y < context.Height; y++)
 79 | 		{
 80 | 			var pixel = context.GetRawPixel(x, y);
 81 | 			var average = Convert.ToByte((pixel.Red + pixel.Green + pixel.Blue)/3d);
 82 | 			context.SetPixel(x, y, pixel.Alpha, average, average, average);
 83 | 		}
 84 | }
85 | 86 | **Animated Gif Encoding** 87 |
using (var image = Image.FromFile(""))
 88 | using (var gif = File.OpenWrite(""))
 89 | using (var encoder = new GifEncoder(gif))
 90 | 	for (var i = 0; i < 360; i += 10)
 91 | 		using (var frame = image.Rotate(i, false))
 92 | 		{
 93 | 			encoder.AddFrame(frame);
 94 | 		}
95 | 96 | **Font Borders** 97 |
var img = new Bitmap(600, 200);
 98 | using (var gfx = Graphics.FromImage(img))
 99 | using (var font = new Font(SystemFonts.DefaultFont.FontFamily, 50))
100 | {
101 | 	gfx.SmoothingMode = SmoothingMode.AntiAlias;
102 | 	gfx.DrawString("ABCabc123", font, Brushes.Black, 0, 0, 50,
103 | 		new[] {Color.Red, Color.Green, Color.Blue},
104 | 		new[] {0f, 0.5f, 1f});
105 | }
106 | --------------------------------------------------------------------------------