├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── Slideshow.ico ├── ThumbnailSharp.sln └── ThumbnailSharp ├── Properties └── AssemblyInfo.cs ├── ThumbnailCreator.cs └── ThumbnailSharp.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | /ThumbnailSharp/ThumbnailSharp.csproj.nuspec 263 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Mirza Ghulam Rasyid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ThumbnailSharp 2 | A specialized library to create an image thumbnail from various sources with better result and supports different image formats. A Thumbnail is something that's not very important sometimes, but for softwares/web apps that require a thumbnail to be uploaded to their databases to be used later becomes so vital. And if we just need to create a simple thumbnail, why do we need a big image composition library that holds unnecessary methods for us? Here, we introduce a simple but powerful library for creating a nice thumbnail either from local or internet (supports async/await) that produces better result than **Image.GetThumbnailImage Method** from **System.Drawing.dll**. You can consume the result of operation either as an array of bytes or a stream. 3 | 4 | Here are some samples: 5 | 6 | **Original Image (Landscape)** 7 | 8 | ![landscape-image](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/landscape.jpg) 9 | 10 | **Thumbnail (Jpeg)** 11 | 12 | *size is set to 250* 13 | 14 | ![landscape-image-thumbnail](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/landscape-thumbnail.jpg) 15 | 16 | 17 | *size is set to 450* 18 | 19 | ![landscape-image-thumbnail](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/landscape-thumbnail-450.jpg) 20 | 21 | 22 | 23 | 24 | 25 | **Original Image (Portrait)** 26 | 27 | ![portrait-image](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/portrait.jpg) 28 | 29 | **Thumbnail (Jpeg)** 30 | 31 | *size is set to 250* 32 | 33 | ![portrait-image-thumbnail](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/portrait-thumbnail.jpg) 34 | 35 | *size is set to 450* 36 | 37 | ![portrait-image-thumbnail](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/portrait-thumbnail-450.jpg) 38 | 39 | 40 | 41 | 42 | 43 | **Original Image (Square/Proportional)** 44 | 45 | ![square-image](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/proportional.jpg) 46 | 47 | **Thumbnail (Jpeg)** 48 | 49 | *size is set to 250* 50 | 51 | ![square-image](https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp.Client/master/AllSamples/Samples/Local/proportional-thumbnail.jpg) 52 | 53 | 54 | 55 | 56 | 57 | 58 | How does it work? 59 | Simple, you just need to pass thumbnail size (aspect ratio will be reserved), image source, and image format. 60 | 61 | **Get thumbnail from internet source** 62 | 63 | ```csharp 64 | byte[] resultBytes = await new ThumbnailCreator().CreateThumbnailBytesAsync( 65 | thumbnailSize: 250, 66 | urlAddress: new Uri("http://www.sample-image.com/image.jpg",UriKind.Absolute), 67 | imageFormat: Format.Jpeg 68 | ); 69 | // or 70 | Stream resultStream = await new ThumbnailCreator().CreateThumbnailStreamAsync( 71 | thumbnailSize: 250, 72 | urlAddress: new Uri("http://www.sample-image.com/image.png",UriKind.Absolute), 73 | imageFormat: Format.Png 74 | ); 75 | ``` 76 | 77 | **Get thumbnail from local source** 78 | 79 | ```csharp 80 | byte[] resultBytes = new ThumbnailCreator().CreateThumbnailBytes( 81 | thumbnailSize: 300, 82 | imageFileLocation: @"C:\images\image.bmp", 83 | imageFormat: Format.Bmp 84 | ); 85 | //or 86 | Stream resultStream = new ThumbnailCreator().CreateThumbnailStream( 87 | thumbnailSize: 300, 88 | imageFileLocation: @"C:\images\image.bmp", 89 | imageFormat: Format.Bmp 90 | ); 91 | ``` 92 | 93 | **Get thumbnail from image stream** 94 | 95 | ```csharp 96 | byte[] resultBytes = new ThumbnailCreator().CreateThumbnailBytes( 97 | thumbnailSize: 300, 98 | imageStream: new FileStream(@"C:\images\image.jpg",FileMode.Open,FileAccess.ReadWrite), 99 | imageFormat: Format.Jpeg 100 | ); 101 | //or 102 | Stream resultStream = new ThumbnailCreator().CreateThumbnailStream( 103 | thumbnailSize: 300, 104 | imageStream: new FileStream(@"C:\images\image.jpg",FileMode.Open,FileAccess.ReadWrite), 105 | imageFormat: Format.Jpeg 106 | ); 107 | ``` 108 | 109 | **Get thumbnail from image bytes** 110 | 111 | ```csharp 112 | byte[] buffer = GetImageBytes(); //this is just fictitious method to get image data in bytes 113 | 114 | byte[] resultBytes = new ThumbnailCreator().CreateThumbnailBytes( 115 | thumbnailSize: 300, 116 | imageBytes: buffer, 117 | imageFormat: Format.Gif 118 | ); 119 | //or 120 | Stream resultStream = new ThumbnailCreator().CreateThumbnailStream( 121 | thumbnailSize: 300, 122 | imageBytes: buffer, 123 | imageFormat: Format.Tiff 124 | ); 125 | ``` 126 | 127 | 128 | 129 | **Take a look our softwares that were built using this library:** 130 | 131 | ### [ThumbnailSharp.Clients](https://github.com/mirzaevolution/ThumbnailSharp.Client) 132 | 133 | 134 | --- 135 | 136 | Ready to taste it? 137 | 138 | #### Install from [Nuget.Org](https://www.nuget.org/packages/ThumbnailSharp/1.0.0) 139 | 140 | ``` 141 | Install-Package ThumbnailSharp -Version 1.0.0 142 | ``` 143 | 144 | --- 145 | 146 | 147 | 148 | Created by: **[Mirza Ghulam Rasyid](https://twitter.com/mirzaevolution)** 149 | -------------------------------------------------------------------------------- /Slideshow.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirzaevolution/ThumbnailSharp/66cf7a4d50d6109829700f682364ea5cfc487df3/Slideshow.ico -------------------------------------------------------------------------------- /ThumbnailSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThumbnailSharp", "ThumbnailSharp\ThumbnailSharp.csproj", "{0F6E03AA-E5D9-4E2C-BE26-A7C396705BDF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {0F6E03AA-E5D9-4E2C-BE26-A7C396705BDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {0F6E03AA-E5D9-4E2C-BE26-A7C396705BDF}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {0F6E03AA-E5D9-4E2C-BE26-A7C396705BDF}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {0F6E03AA-E5D9-4E2C-BE26-A7C396705BDF}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {3FA8D01B-D065-4A3C-A311-D634F2C08FB1} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /ThumbnailSharp/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("ThumbnailSharp")] 9 | [assembly: AssemblyDescription("A simple library to create a flexibel thumbnail from an image.")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Mirza Ghulam Rasyid")] 12 | [assembly: AssemblyProduct("ThumbnailSharp")] 13 | [assembly: AssemblyCopyright("Copyright © 2017 Mirza Ghulam Rasyid")] 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("0f6e03aa-e5d9-4e2c-be26-a7c396705bdf")] 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 | -------------------------------------------------------------------------------- /ThumbnailSharp/ThumbnailCreator.cs: -------------------------------------------------------------------------------- 1 | /*MIT License 2 | 3 | Copyright(c) 2017 Mirza Ghulam Rasyid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | */ 23 | 24 | using System; 25 | using System.Drawing; 26 | using System.Drawing.Drawing2D; 27 | using System.Drawing.Imaging; 28 | using System.IO; 29 | using System.Net.Http; 30 | using System.Threading.Tasks; 31 | 32 | 33 | namespace ThumbnailSharp 34 | { 35 | /// 36 | /// Image format to use when creating a thumbnail. 37 | /// 38 | public enum Format 39 | { 40 | Jpeg, 41 | Bmp, 42 | Png, 43 | Gif, 44 | Tiff 45 | 46 | } 47 | /// 48 | /// make thumbnail force by ratio 49 | /// 50 | public enum Ratio 51 | { 52 | 53 | Landscape, 54 | Portrait 55 | } 56 | /// 57 | /// Thumbnail class that holds various methods to create an image thumbnail. 58 | /// 59 | public class ThumbnailCreator 60 | { 61 | Ratio? forceRatio = null; 62 | public ThumbnailCreator() : this(null) 63 | { 64 | } 65 | public ThumbnailCreator(Ratio? forceRatio) 66 | { 67 | 68 | this.forceRatio = forceRatio; 69 | } 70 | 71 | private Stream GetStreamFromFileLocation(string imageLocation) 72 | { 73 | if (!File.Exists(imageLocation)) 74 | { 75 | throw new FileNotFoundException("fileNotFound:" + imageLocation); 76 | } 77 | return File.OpenRead(imageLocation); 78 | } 79 | Ratio GetRatio(Ratio? forceRatio, float actualWidth, float actualHeight) 80 | { 81 | if (forceRatio.HasValue) 82 | { 83 | return forceRatio.Value; 84 | } 85 | return actualWidth >= actualHeight ? Ratio.Landscape : Ratio.Portrait; 86 | 87 | } 88 | private Bitmap CreateBitmapThumbnail(uint thumbnailSize, string imageFileLocation) 89 | { 90 | return CreateBitmapThumbnail(thumbnailSize, GetStreamFromFileLocation(imageFileLocation)); 91 | Bitmap bitmap = null; 92 | Image image = null; 93 | float actualHeight = default(float); 94 | float actualWidth = default(float); 95 | uint thumbnailHeight = default(uint); 96 | uint thumbnailWidth = default(uint); 97 | try 98 | { 99 | image = Image.FromFile(imageFileLocation); 100 | } 101 | catch 102 | { 103 | if (image != null) 104 | image = null; 105 | } 106 | if (image != null) 107 | { 108 | actualHeight = image.Height; 109 | actualWidth = image.Width; 110 | if (forceRatio.Value == Ratio.Portrait || actualHeight > actualWidth) 111 | { 112 | if ((uint)actualHeight <= thumbnailSize) 113 | return (Bitmap)image; 114 | //throw new Exception("Thumbnail size must be less than actual height (portrait image)"); 115 | thumbnailHeight = thumbnailSize; 116 | thumbnailWidth = (uint)((actualWidth / actualHeight) * thumbnailSize); 117 | } 118 | else if (forceRatio.Value == Ratio.Landscape && actualWidth > actualHeight) 119 | { 120 | 121 | if ((uint)actualWidth <= thumbnailSize) 122 | return (Bitmap)image; 123 | //throw new Exception("Thumbnail size must be less than actual width (landscape image)"); 124 | thumbnailWidth = thumbnailSize; 125 | thumbnailHeight = (uint)((actualHeight / actualWidth) * thumbnailSize); 126 | } 127 | else 128 | { 129 | if ((uint)actualWidth <= thumbnailSize) 130 | return (Bitmap)image; 131 | //throw new Exception("Thumbnail size must be less than image's size"); 132 | thumbnailWidth = thumbnailSize; 133 | thumbnailHeight = thumbnailSize; 134 | } 135 | try 136 | { 137 | 138 | bitmap = new Bitmap((int)thumbnailWidth, (int)thumbnailHeight); 139 | Graphics resizedImage = Graphics.FromImage(bitmap); 140 | resizedImage.InterpolationMode = InterpolationMode.HighQualityBicubic; 141 | resizedImage.CompositingQuality = CompositingQuality.HighQuality; 142 | resizedImage.SmoothingMode = SmoothingMode.HighQuality; 143 | resizedImage.DrawImage(image, 0, 0, thumbnailWidth, thumbnailHeight); 144 | } 145 | catch 146 | { 147 | if (bitmap != null) 148 | bitmap = null; 149 | } 150 | } 151 | return bitmap; 152 | } 153 | private Bitmap CreateBitmapThumbnail(uint thumbnailSize, Stream imageStream) 154 | { 155 | Bitmap bitmap = null; 156 | System.Drawing.Image image = null; 157 | float actualHeight = default(float); 158 | float actualWidth = default(float); 159 | uint thumbnailHeight = default(uint); 160 | uint thumbnailWidth = default(uint); 161 | try 162 | { 163 | image = Image.FromStream(imageStream); 164 | } 165 | catch 166 | { 167 | if (image != null) 168 | image = null; 169 | } 170 | if (image != null) 171 | { 172 | actualHeight = image.Height; 173 | actualWidth = image.Width; 174 | if (GetRatio(forceRatio,actualWidth, actualHeight)== Ratio.Portrait) 175 | { 176 | if ((uint)actualHeight <= thumbnailSize) 177 | return (Bitmap)image; 178 | //throw new Exception("Thumbnail size must be less than actual height (portrait image)"); 179 | thumbnailHeight = thumbnailSize; 180 | thumbnailWidth = (uint)((actualWidth / actualHeight) * thumbnailSize); 181 | } 182 | else if (GetRatio(forceRatio, actualWidth, actualHeight) == Ratio.Landscape) 183 | { 184 | 185 | if ((uint)actualWidth <= thumbnailSize) 186 | return (Bitmap)image; 187 | //throw new Exception("Thumbnail size must be less than actual width (landscape image)"); 188 | thumbnailWidth = thumbnailSize; 189 | thumbnailHeight = (uint)((actualHeight / actualWidth) * thumbnailSize); 190 | } 191 | else 192 | { 193 | if ((uint)actualWidth <= thumbnailSize) 194 | return (Bitmap)image; 195 | //throw new Exception("Thumbnail size must be less than image's size"); 196 | thumbnailWidth = thumbnailSize; 197 | thumbnailHeight = thumbnailSize; 198 | } 199 | try 200 | { 201 | bitmap = new Bitmap((int)thumbnailWidth, (int)thumbnailHeight); 202 | Graphics resizedImage = Graphics.FromImage(bitmap); 203 | resizedImage.InterpolationMode = InterpolationMode.HighQualityBicubic; 204 | resizedImage.CompositingQuality = CompositingQuality.HighQuality; 205 | resizedImage.SmoothingMode = SmoothingMode.HighQuality; 206 | resizedImage.DrawImage(image, 0, 0, thumbnailWidth, thumbnailHeight); 207 | } 208 | catch 209 | { 210 | if (bitmap != null) 211 | bitmap = null; 212 | } 213 | } 214 | return bitmap; 215 | } 216 | private ImageFormat GetImageFormat(Format format) 217 | { 218 | switch (format) 219 | { 220 | case Format.Jpeg: 221 | return ImageFormat.Jpeg; 222 | case Format.Bmp: 223 | return ImageFormat.Bmp; 224 | case Format.Png: 225 | return ImageFormat.Png; 226 | case Format.Gif: 227 | return ImageFormat.Gif; 228 | default: 229 | return ImageFormat.Tiff; 230 | } 231 | } 232 | private async Task GetImageStreamFromUrl(Uri urlAddress) 233 | { 234 | Stream result = null; 235 | try 236 | { 237 | byte[] bytes = await GetImageBytesFromUrl(urlAddress); 238 | result = new MemoryStream(bytes); 239 | } 240 | catch 241 | { 242 | result = null; 243 | } 244 | return result; 245 | } 246 | private async Task GetImageBytesFromUrl(Uri urlAddress) 247 | { 248 | byte[] buffer = null; 249 | try 250 | { 251 | using (HttpClient client = new HttpClient()) 252 | { 253 | buffer = await client.GetByteArrayAsync(urlAddress); 254 | } 255 | } 256 | catch 257 | { 258 | buffer = null; 259 | } 260 | return buffer; 261 | } 262 | 263 | /// 264 | /// Create a thumbnail from file and returns as stream. 265 | /// 266 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 267 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 268 | /// Correct image file location. 269 | /// Image format to use. 270 | /// A thumbnail image as stream. Returns null if it fails. 271 | /// 'imageFileLocation' is null. 272 | /// 'imageFileLocation' does not exist. 273 | public Stream CreateThumbnailStream(uint thumbnailSize, string imageFileLocation, Format imageFormat) 274 | { 275 | if (String.IsNullOrEmpty(imageFileLocation)) 276 | throw new ArgumentNullException(nameof(imageFileLocation), "'imageFileLocation' cannot be null"); 277 | if (!File.Exists(imageFileLocation)) 278 | throw new FileNotFoundException($"'{imageFileLocation}' cannot be found"); 279 | Bitmap bitmap = CreateBitmapThumbnail(thumbnailSize, imageFileLocation); 280 | if (bitmap != null) 281 | { 282 | MemoryStream stream = new MemoryStream(); 283 | bitmap.Save(stream, GetImageFormat(imageFormat)); 284 | stream.Position = 0; 285 | return stream; 286 | } 287 | return null; 288 | } 289 | /// 290 | /// Create a thumbnail from image stream and returns as stream. 291 | /// 292 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 293 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 294 | /// Valid image stream object. 295 | /// Image format to use. 296 | /// A thumbnail image as stream. Returns null if it fails. 297 | /// 'imageStream' is null. 298 | public Stream CreateThumbnailStream(uint thumbnailSize, Stream imageStream, Format imageFormat) 299 | { 300 | if (imageStream == null) 301 | throw new ArgumentNullException(nameof(imageStream), "'imageStream' cannot be null"); 302 | Bitmap bitmap = CreateBitmapThumbnail(thumbnailSize, imageStream); 303 | if (bitmap != null) 304 | { 305 | MemoryStream stream = new MemoryStream(); 306 | bitmap.Save(stream, GetImageFormat(imageFormat)); 307 | stream.Position = 0; 308 | return stream; 309 | } 310 | return null; 311 | } 312 | /// 313 | /// Create a thumbnail from image in bytes and returns as stream. 314 | /// 315 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 316 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 317 | /// Valid image bytes array. 318 | /// Image format to use. 319 | /// A thumbnail image as stream. Returns null if it fails. 320 | /// 'imageBytes' is null. 321 | public Stream CreateThumbnailStream(uint thumbnailSize, byte[] imageBytes, Format imageFormat) 322 | { 323 | if (imageBytes == null) 324 | throw new ArgumentNullException(nameof(imageBytes), "'imageStream' cannot be null"); 325 | Bitmap bitmap = CreateBitmapThumbnail(thumbnailSize, new MemoryStream(imageBytes)); 326 | if (bitmap != null) 327 | { 328 | MemoryStream stream = new MemoryStream(); 329 | bitmap.Save(stream, GetImageFormat(imageFormat)); 330 | stream.Position = 0; 331 | return stream; 332 | } 333 | return null; 334 | } 335 | /// 336 | /// Create a thumbnail from file and returns as bytes. 337 | /// 338 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 339 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 340 | /// Correct image file location. 341 | /// Image format to use. 342 | /// A thumbnail image as bytes. Returns null if it fails. 343 | /// 'imageFileLocation' is null. 344 | /// 'imageFileLocation' does not exist. 345 | public byte[] CreateThumbnailBytes(uint thumbnailSize, string imageFileLocation, Format imageFormat) 346 | { 347 | if (String.IsNullOrEmpty(imageFileLocation)) 348 | throw new ArgumentNullException(nameof(imageFileLocation), "'imageFileLocation' cannot be null"); 349 | if (!File.Exists(imageFileLocation)) 350 | throw new FileNotFoundException($"'{imageFileLocation}' cannot be found"); 351 | Stream stream = CreateThumbnailStream(thumbnailSize, imageFileLocation, imageFormat); 352 | if (stream != null) 353 | { 354 | byte[] streamBytes = new byte[stream.Length]; 355 | stream.Read(streamBytes, 0, streamBytes.Length); 356 | return streamBytes; 357 | } 358 | return null; 359 | } 360 | /// 361 | /// Create a thumbnail from image stream and returns as bytes. 362 | /// 363 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 364 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 365 | /// Valid image stream object. 366 | /// Image format to use. 367 | /// A thumbnail image as bytes. Returns null if it fails. 368 | /// 'imageStream' is null. 369 | public byte[] CreateThumbnailBytes(uint thumbnailSize, Stream imageStream, Format imageFormat) 370 | { 371 | if (imageStream == null) 372 | throw new ArgumentNullException(nameof(imageStream), "'imageStream' cannot be null"); 373 | 374 | Stream stream = CreateThumbnailStream(thumbnailSize, imageStream, imageFormat); 375 | if (stream != null) 376 | { 377 | byte[] streamBytes = new byte[stream.Length]; 378 | stream.Read(streamBytes, 0, streamBytes.Length); 379 | return streamBytes; 380 | } 381 | return null; 382 | } 383 | /// 384 | /// Create a thumbnail from image in bytes and returns as bytes. 385 | /// 386 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 387 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 388 | /// Valid image bytes array. 389 | /// Image format to use. 390 | /// A thumbnail image as bytes. Returns null if it fails. 391 | /// 'imageBytes' is null. 392 | public byte[] CreateThumbnailBytes(uint thumbnailSize, byte[] imageBytes, Format imageFormat) 393 | { 394 | if (imageBytes == null) 395 | throw new ArgumentNullException(nameof(imageBytes), "'imageStream' cannot be null"); 396 | Stream stream = CreateThumbnailStream(thumbnailSize, imageBytes, imageFormat); 397 | if (stream != null) 398 | { 399 | byte[] streamBytes = new byte[stream.Length]; 400 | stream.Read(streamBytes, 0, streamBytes.Length); 401 | return streamBytes; 402 | } 403 | return null; 404 | } 405 | 406 | 407 | /// 408 | /// Create a thumbnail from valid image url asynchronously. 409 | /// 410 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 411 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 412 | /// Valid absolute url address with proper scheme. 413 | /// Image format to use. 414 | /// A thumbnail image as stream. Returns null if it fails. 415 | /// 'urlAddress' is null. 416 | public async Task CreateThumbnailStreamAsync(uint thumbnailSize, Uri urlAddress, Format imageFormat) 417 | { 418 | if (urlAddress == null) 419 | throw new ArgumentNullException(nameof(urlAddress), "'urlAddress' cannot be null"); 420 | Stream result = null; 421 | Stream stream = await GetImageStreamFromUrl(urlAddress); 422 | if (stream != null) 423 | { 424 | result = CreateThumbnailStream(thumbnailSize, stream, imageFormat); 425 | } 426 | return result; 427 | } 428 | 429 | /// 430 | /// Create a thumbnail from valid image url asynchronously. 431 | /// 432 | /// Thumbnail size. For portrait image, thumbnail size must be less than its height. 433 | /// For landscape image, thumbnail size must be less than its width. For the same size image (Proportional), thumbnail size must be less than its width and height. 434 | /// Valid absolute url address with proper scheme. 435 | /// Image format to use. 436 | /// A thumbnail image as bytes. Returns null if it fails. 437 | /// 'urlAddress' is null. 438 | public async Task CreateThumbnailBytesAsync(uint thumbnailSize, Uri urlAddress, Format imageFormat) 439 | { 440 | if (urlAddress == null) 441 | throw new ArgumentNullException(nameof(urlAddress), "'urlAddress' cannot be null"); 442 | byte[] result = null; 443 | byte[] imageBytes = await GetImageBytesFromUrl(urlAddress); 444 | if (imageBytes != null) 445 | { 446 | result = CreateThumbnailBytes(thumbnailSize, imageBytes, imageFormat); 447 | } 448 | return result; 449 | } 450 | 451 | 452 | 453 | } 454 | } 455 | -------------------------------------------------------------------------------- /ThumbnailSharp/ThumbnailSharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {0F6E03AA-E5D9-4E2C-BE26-A7C396705BDF} 8 | Library 9 | Properties 10 | ThumbnailSharp 11 | ThumbnailSharp 12 | v4.5 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | bin\Debug\ThumbnailSharp.xml 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | bin\Release\ThumbnailSharp.xml 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | --------------------------------------------------------------------------------