├── .editorconfig
├── .gitattributes
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
├── funding.yml
└── stale.yml
├── .gitignore
├── ImageProcessor.ruleset
├── ImageProcessor.sln
├── LICENSE
├── README.md
├── src
├── ImageProcessor.Plugins.WebP
│ ├── Formats
│ │ ├── NativeMethods.cs
│ │ └── WebPFormat.cs
│ ├── ImageProcessor.Plugins.WebP.csproj
│ ├── README.md
│ └── Resources
│ │ └── Unmanaged
│ │ ├── README.txt
│ │ ├── x64
│ │ └── libwebp.dll
│ │ └── x86
│ │ └── libwebp.dll
└── ImageProcessor
│ ├── Bgra32.cs
│ ├── Common
│ ├── Exceptions
│ │ ├── ImageFormatException.cs
│ │ ├── ImageProcessingException.cs
│ │ ├── Logging
│ │ │ ├── DefaultLogger.cs
│ │ │ └── ILogger.cs
│ │ └── QuantizationException.cs
│ ├── Extensions
│ │ ├── AssemblyExtensions.cs
│ │ ├── DoubleExtensions.cs
│ │ ├── ImageExtensions.cs
│ │ ├── IntegerExtensions.cs
│ │ └── StreamExtensions.cs
│ └── Helpers
│ │ ├── BigEndianBitConverter.cs
│ │ ├── ComputerArchitectureInfo.cs
│ │ ├── EndianBitConverter.cs
│ │ ├── Endianness.cs
│ │ ├── EnumerableUtilities.cs
│ │ ├── FormatUtilities.cs
│ │ ├── GeometryUtilities.cs
│ │ ├── IComputerArchitectureInfo.cs
│ │ ├── LittleEndianBitConverter.cs
│ │ └── NumberUtilities.cs
│ ├── Configuration
│ ├── ImageProcessorBootstrapper.cs
│ ├── NativeBinaryFactory.cs
│ └── NativeMethods.cs
│ ├── FastBitmap.cs
│ ├── Formats
│ ├── BitDepth.cs
│ ├── BitmapFormat.cs
│ ├── FormatBase.cs
│ ├── GifDecoder.cs
│ ├── GifEncoder.cs
│ ├── GifFormat.cs
│ ├── GifFrame.cs
│ ├── IImageFormat.cs
│ ├── JpegFormat.cs
│ ├── PngFormat.cs
│ └── TiffFormat.cs
│ ├── FrameProcessingMode.cs
│ ├── ImageFactory.Processing.cs
│ ├── ImageFactory.cs
│ ├── ImageProcessor.csproj
│ ├── Metadata
│ ├── ExifBitConverter.cs
│ ├── ExifPropertyTag.cs
│ ├── ExifPropertyTagConstants.cs
│ ├── ExifPropertyTagType.cs
│ ├── ImageFactoryMetaExtensions.cs
│ ├── Int32Converter.cs
│ ├── PropertyTagResolutionUnit.cs
│ └── Rational.cs
│ ├── MetadataMode.cs
│ ├── Processing
│ ├── Adjustments.cs
│ ├── Alpha.cs
│ ├── AutoRotate.cs
│ ├── BackgroundColor.cs
│ ├── Brightness.cs
│ ├── ColorMatrixProcessor.cs
│ ├── ColorMatrixRangedProcessor.cs
│ ├── Contrast.cs
│ ├── Convolution
│ │ ├── Convolution2DProcessor.cs
│ │ ├── ConvolutionProcessor.cs
│ │ ├── EdgeDetection2DProcessor.cs
│ │ ├── EdgeDetectionOperators.cs
│ │ ├── EdgeDetectionProcessor.cs
│ │ ├── Kayyali.cs
│ │ ├── Laplacian3x3.cs
│ │ ├── Laplacian5x5.cs
│ │ ├── LaplacianOfGaussian.cs
│ │ ├── Prewitt.cs
│ │ ├── RobertsCross.cs
│ │ ├── Scharr.cs
│ │ └── Sobel.cs
│ ├── Crop.cs
│ ├── Grayscale.cs
│ ├── Hue.cs
│ ├── IGraphicsProcessor.cs
│ ├── KnownColorMatrices.cs
│ ├── Pixelate.cs
│ ├── Resize.cs
│ ├── ResizeHelper.cs
│ └── Saturation.cs
│ └── Quantizers
│ ├── IQuantizer.cs
│ ├── OctreeQuantizer.cs
│ ├── Quantizer.cs
│ └── WuQuantizer
│ ├── Box.cs
│ ├── ColorMoment.cs
│ ├── CubeCut.cs
│ ├── Histogram.cs
│ ├── IWuQuantizer.cs
│ ├── ImageBuffer.cs
│ ├── PaletteColorHistory.cs
│ ├── PaletteLookup.cs
│ ├── WuQuantizer.cs
│ └── WuQuantizerBase.cs
├── stylecop.json
└── tests
├── ImageProcessor.Tests
├── FastBitmapTests.cs
├── ImageDeepCopyTests.cs
├── ImageExtensionTests.cs
├── ImageFactoryEncodingTests.cs
├── ImageFactoryExtensions.cs
├── ImageProcessor.Tests.csproj
├── ImagesSimilarityException.cs
├── Processing
│ ├── AlphaTests.cs
│ ├── AutoRotateTests.cs
│ ├── BackgroundColorTests.cs
│ ├── BrightnessTests.cs
│ ├── ContrastTests.cs
│ ├── CropTests.cs
│ ├── DetectEdgesTests.cs
│ ├── HueTests.cs
│ ├── PixelateTests.cs
│ ├── ResizeTests.cs
│ └── SaturationTests.cs
├── TestFiles.cs
├── TestUtils.cs
└── xunit.runner.json
└── Images
└── Input
├── 4.sm.webp
├── Teeth.png
├── animated-bird.gif
├── animated-meter.gif
├── animated-pattern.gif
├── animated-startrek.gif
├── animated-zivan.gif
├── autorotate-landscape-2.jpg
├── b.jpg
├── color-tests
├── hi-color.png
├── hi-contrast.jpg
└── hi-saturation.jpg
├── exif-crop-issue-559.jfif
├── exif
├── autorotate.jpg
├── exif-Tulips.jpg
└── exif-rocks.jpg
├── format-Penguins-8bit.png
├── format-Penguins.bmp
├── format-Penguins.gif
├── format-Penguins.jpg
├── format-Penguins.png
├── format-Penguins.tif
├── format-Penguins.webp
├── gamma
├── gamma-1.0-or-2.2.png
├── gamma-dalai-lama-gray-tft.jpg
├── gamma-dalai-lama-gray.jpg
├── gamma-fly.jpg
└── gamma-saturn.jpg
├── icc-profiles
├── cmyk-profile-euroscale.jpg
├── profile-adobe-rgb.jpg
└── profile-srgb.jpg
├── imageprocessor
├── mask
│ └── mask.png
└── overlay
│ ├── monster.png
│ └── monster24bit.png
├── stretched.jpg
├── text.png
└── trans.gif
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to:
3 | # treat as text and
4 | # normalize to Unix-style line endings
5 | ###############################################################################
6 | * text eol=lf
7 |
8 | ###############################################################################
9 | # Set explicit file behavior to:
10 | # treat as text and
11 | # normalize to Unix-style line endings
12 | ###############################################################################
13 | *.asm text eol=lf
14 | *.c text eol=lf
15 | *.clj text eol=lf
16 | *.cmd text eol=lf
17 | *.cpp text eol=lf
18 | *.css text eol=lf
19 | *.cxx text eol=lf
20 | *.config text eol=lf
21 | *.DotSettings text eol=lf
22 | *.erl text eol=lf
23 | *.fs text eol=lf
24 | *.fsx text eol=lf
25 | *.h text eol=lf
26 | *.htm text eol=lf
27 | *.html text eol=lf
28 | *.hs text eol=lf
29 | *.hxx text eol=lf
30 | *.java text eol=lf
31 | *.js text eol=lf
32 | *.json text eol=lf
33 | *.less text eol=lf
34 | *.lisp text eol=lf
35 | *.lua text eol=lf
36 | *.m text eol=lf
37 | *.md text eol=lf
38 | *.php text eol=lf
39 | *.props text eol=lf
40 | *.ps1 text eol=lf
41 | *.py text eol=lf
42 | *.rb text eol=lf
43 | *.resx text eol=lf
44 | *.runsettings text eol=lf
45 | *.ruleset text eol=lf
46 | *.sass text eol=lf
47 | *.scss text eol=lf
48 | *.sh text eol=lf
49 | *.sql text eol=lf
50 | *.svg text eol=lf
51 | *.targets text eol=lf
52 | *.tt text eol=crlf
53 | *.ttinclude text eol=crlf
54 | *.txt text eol=lf
55 | *.vb text eol=lf
56 | *.yml text eol=lf
57 |
58 | ###############################################################################
59 | # Set explicit file behavior to:
60 | # treat as text
61 | # normalize to Unix-style line endings and
62 | # diff as csharp
63 | ###############################################################################
64 | *.cs text eol=lf diff=csharp
65 |
66 | ###############################################################################
67 | # Set explicit file behavior to:
68 | # treat as text
69 | # normalize to Unix-style line endings and
70 | # use a union merge when resoling conflicts
71 | ###############################################################################
72 | *.csproj text eol=lf merge=union
73 | *.dbproj text eol=lf merge=union
74 | *.fsproj text eol=lf merge=union
75 | *.ncrunchproject text eol=lf merge=union
76 | *.vbproj text eol=lf merge=union
77 |
78 | ###############################################################################
79 | # Set explicit file behavior to:
80 | # treat as text
81 | # normalize to Windows-style line endings and
82 | # use a union merge when resoling conflicts
83 | ###############################################################################
84 | *.sln text eol=crlf merge=union
85 |
86 | ###############################################################################
87 | # Set explicit file behavior to:
88 | # treat as binary
89 | ###############################################################################
90 | *.bmp binary
91 | *.dll binary
92 | *.exe binary
93 | *.gif binary
94 | *.jpg binary
95 | *.jpeg binary
96 | *.png binary
97 | *.ttf binary
98 | *.tif binary
99 | *.tiff binary
100 | *.snk binary
101 |
102 | ###############################################################################
103 | # Set explicit file behavior to:
104 | # diff as plain text
105 | ###############################################################################
106 | *.doc diff=astextplain
107 | *.docx diff=astextplain
108 | *.dot diff=astextplain
109 | *.pdf diff=astextplain
110 | *.pptx diff=astextplain
111 | *.rtf diff=astextplain
112 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute to ImageProcessor
2 |
3 | #### **Did you find a bug?**
4 |
5 | - Please **ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/JimBobSquarePants/ImageProcessor/issues).
6 |
7 | - If you're unable to find an open issue addressing the problem, please [open a new one](https://github.com/JimBobSquarePants/ImageProcessor/issues/new). Be sure to include a **title, the applicable version, a clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. Please do not hijack existing issues.
8 |
9 | #### **Did you write a patch that fixes a bug?**
10 |
11 | * Open a new GitHub pull request with the patch.
12 |
13 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
14 |
15 | * Before submitting, please ensure that your code matches the existing coding patterns and practise as demonstrated in the repository. These follow strict Stylecop rules :cop:.
16 |
17 | #### **Do you intend to add a new feature or change an existing one?**
18 |
19 | * Suggest your change in the [ImageProcessor Gitter Chat Room](https://gitter.im/JimBobSquarePants/ImageProcessor) and start writing code.
20 |
21 | * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.
22 |
23 | #### **Do you have questions about consuming the library or the source code?**
24 |
25 | * Ask any question about how to use ImageSharp in the [ImageProcessor Gitter Chat Room](https://gitter.im/JimBobSquarePants/ImageProcessor).
26 |
27 | And please remember. ImageProcessor is the work of a very, very, small number of developers who struggle balancing time to contribute to the project with family time and work commitments. We encourage you to pitch in and help make our vision of simple accessible imageprocessing available to all. Open Source can only exist with your help.
28 |
29 | Thanks for reading!
30 |
31 | James Jackson-South :heart:
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Prerequisites
2 |
3 | - [ ] I have written a descriptive issue title
4 | - [ ] I have verified that I am running the latest version of ImageProcessor
5 | - [ ] I have verified if the problem exist in both `DEBUG` and `RELEASE` mode
6 | - [ ] I have searched [open](https://github.com/JimBobSquarePants/ImageProcessor/issues) and [closed](https://github.com/JimBobSquarePants/ImageProcessor/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported
7 |
8 | ### Description
9 |
10 |
11 | ### Steps to Reproduce
12 |
13 |
14 | ### System Configuration
15 |
16 |
17 | - ImageProcessor version:
18 | - ImageProcessor.Web version (if applicable)
19 | - Other ImageProcessor packages and versions:
20 | - Environment (Operating system, version and so on):
21 | - .NET Framework version:
22 | - Additional information:
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Prerequisites
2 |
3 | - [ ] I have written a descriptive pull-request title
4 | - [ ] I have verified that there are no overlapping [pull-requests](https://github.com/JimBobSquarePants/ImageProcessor/pulls) open
5 | - [ ] I have verified that I am following matches the existing coding patterns and practise as demonstrated in the repository. These follow strict Stylecop rules :cop:.
6 | - [ ] I have provided test coverage for my change (where applicable)
7 |
8 | ### Description
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.github/funding.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: JimBobSquarePants
4 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 60
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 7
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | - bug
10 | # Label to use when marking an issue as stale
11 | staleLabel: no activity
12 | # Comment to post when marking an issue as stale. Set to `false` to disable
13 | markComment: >
14 | This issue has been automatically marked as stale because it has not had
15 | recent activity. It will be closed if no further activity occurs. Thank you
16 | for your contributions.
17 | # Comment to post when closing a stale issue. Set to `false` to disable
18 | closeComment: false
--------------------------------------------------------------------------------
/.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 | src/**/build/
21 | tests/**/build/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 |
26 | # Visual Studo 2015 cache/options directory
27 | .vs/
28 |
29 | # Jetbrains Rider cache/options directory
30 | .idea/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # ASP.NET 5
46 | project.lock.json
47 | artifacts/
48 |
49 | *_i.c
50 | *_p.c
51 | *_i.h
52 | *.ilk
53 | *.meta
54 | *.obj
55 | *.pch
56 | *.pdb
57 | *.pgc
58 | *.pgd
59 | *.rsp
60 | *.sbr
61 | *.tlb
62 | *.tli
63 | *.tlh
64 | *.tmp
65 | *.tmp_proj
66 | *.log
67 | *.vspscc
68 | *.vssscc
69 | .builds
70 | *.pidb
71 | *.svclog
72 | *.scc
73 |
74 | # Chutzpah Test files
75 | _Chutzpah*
76 |
77 | # Visual C++ cache files
78 | ipch/
79 | *.aps
80 | *.ncb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 |
90 | # TFS 2012 Local Workspace
91 | $tf/
92 |
93 | # Guidance Automation Toolkit
94 | *.gpState
95 |
96 | # ReSharper is a .NET coding add-in
97 | _ReSharper*/
98 | *.[Rr]e[Ss]harper
99 | *.DotSettings.user
100 |
101 | # JustCode is a .NET coding addin-in
102 | .JustCode
103 |
104 | # TeamCity is a build add-in
105 | _TeamCity*
106 |
107 | # DotCover is a Code Coverage Tool
108 | *.dotCover
109 |
110 | # NCrunch
111 | _NCrunch_*
112 | .*crunch*.local.xml
113 |
114 | # MightyMoose
115 | *.mm.*
116 | AutoTest.Net/
117 |
118 | # Web workbench (sass)
119 | .sass-cache/
120 |
121 | # Installshield output folder
122 | [Ee]xpress/
123 |
124 | # DocProject is a documentation generator add-in
125 | DocProject/buildhelp/
126 | DocProject/Help/*.HxT
127 | DocProject/Help/*.HxC
128 | DocProject/Help/*.hhc
129 | DocProject/Help/*.hhk
130 | DocProject/Help/*.hhp
131 | DocProject/Help/Html2
132 | DocProject/Help/html
133 |
134 | # Click-Once directory
135 | publish/
136 |
137 | # Publish Web Output
138 | *.[Pp]ublish.xml
139 | *.azurePubxml
140 | # TODO: Comment the next line if you want to checkin your web deploy settings
141 | # but database connection strings (with potential passwords) will be unencrypted
142 | *.pubxml
143 | *.publishproj
144 |
145 | # NuGet Packages
146 | *.nupkg
147 | # The packages folder can be ignored because of Package Restore
148 | **/packages/*
149 | # except build/, which is used as an MSBuild target.
150 | !**/packages/build/
151 | # Uncomment if necessary however generally it will be regenerated when needed
152 | #!**/packages/repositories.config
153 |
154 | # Windows Azure Build Output
155 | csx/
156 | *.build.csdef
157 |
158 | # Windows Store app package directory
159 | AppPackages/
160 |
161 | # Others
162 | *.[Cc]ache
163 | ClientBin/
164 | ~$*
165 | *~
166 | *.dbmdl
167 | *.dbproj.schemaview
168 | *.pfx
169 | *.publishsettings
170 | node_modules/
171 | bower_components/
172 |
173 | # RIA/Silverlight projects
174 | Generated_Code/
175 |
176 | # Backup & report files from converting an old project file
177 | # to a newer Visual Studio version. Backup files are not needed,
178 | # because we have git ;-)
179 | _UpgradeReport_Files/
180 | Backup*/
181 | UpgradeLog*.XML
182 | UpgradeLog*.htm
183 |
184 | # SQL Server files
185 | *.mdf
186 | *.ldf
187 |
188 | # Business Intelligence projects
189 | *.rdl.data
190 | *.bim.layout
191 | *.bim_*.settings
192 |
193 | # Microsoft Fakes
194 | FakesAssemblies/
195 |
196 | # Node.js Tools for Visual Studio
197 | .ntvs_analysis.dat
198 |
199 | # Visual Studio 6 build log
200 | *.plg
201 |
202 | # Visual Studio 6 workspace options file
203 | *.opt
204 |
205 | **/node_modules
206 | **/node_modules/*
207 |
208 | # ASP.NET 5
209 | project.lock.json
210 | artifacts/
211 |
212 | #BenchmarkDotNet
213 | **/BenchmarkDotNet.Artifacts/
214 |
215 | # Build process
216 | *.csproj.bak
217 |
218 | # Tests TODO: Remove Expected when tests are complete
219 | **/Images/Actual
220 | **/Images/Expected
221 |
222 | !**/Resources/Unmanaged/x64/
223 | !**/Resources/Unmanaged/x86/
224 |
--------------------------------------------------------------------------------
/ImageProcessor.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ImageProcessor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29025.244
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageProcessor", "src\ImageProcessor\ImageProcessor.csproj", "{37B5AB0B-F2D3-418B-BC2B-956AB934CC35}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E12DAFB7-1E0E-4B9F-A997-22F0896ADD0F}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F7EF30FE-9BFD-4EA1-838C-F3D505AB3CD8}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageProcessor.Tests", "tests\ImageProcessor.Tests\ImageProcessor.Tests.csproj", "{47C75531-C0F3-469B-88CF-4F0B00BDD841}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageProcessor.Plugins.WebP", "src\ImageProcessor.Plugins.WebP\ImageProcessor.Plugins.WebP.csproj", "{D8285938-B99E-4B77-BE60-9FBF8A4BD173}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0170E9EB-0F33-45E0-AF6A-7D964F25E73F}"
17 | ProjectSection(SolutionItems) = preProject
18 | .editorconfig = .editorconfig
19 | .gitattributes = .gitattributes
20 | .gitignore = .gitignore
21 | ImageProcessor.ruleset = ImageProcessor.ruleset
22 | README.md = README.md
23 | stylecop.json = stylecop.json
24 | EndProjectSection
25 | EndProject
26 | Global
27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
28 | Debug|Any CPU = Debug|Any CPU
29 | Release|Any CPU = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
32 | {37B5AB0B-F2D3-418B-BC2B-956AB934CC35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {37B5AB0B-F2D3-418B-BC2B-956AB934CC35}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {37B5AB0B-F2D3-418B-BC2B-956AB934CC35}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {37B5AB0B-F2D3-418B-BC2B-956AB934CC35}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {47C75531-C0F3-469B-88CF-4F0B00BDD841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {47C75531-C0F3-469B-88CF-4F0B00BDD841}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {47C75531-C0F3-469B-88CF-4F0B00BDD841}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {47C75531-C0F3-469B-88CF-4F0B00BDD841}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {D8285938-B99E-4B77-BE60-9FBF8A4BD173}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {D8285938-B99E-4B77-BE60-9FBF8A4BD173}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {D8285938-B99E-4B77-BE60-9FBF8A4BD173}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {D8285938-B99E-4B77-BE60-9FBF8A4BD173}.Release|Any CPU.Build.0 = Release|Any CPU
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(NestedProjects) = preSolution
49 | {37B5AB0B-F2D3-418B-BC2B-956AB934CC35} = {E12DAFB7-1E0E-4B9F-A997-22F0896ADD0F}
50 | {47C75531-C0F3-469B-88CF-4F0B00BDD841} = {F7EF30FE-9BFD-4EA1-838C-F3D505AB3CD8}
51 | {D8285938-B99E-4B77-BE60-9FBF8A4BD173} = {E12DAFB7-1E0E-4B9F-A997-22F0896ADD0F}
52 | EndGlobalSection
53 | GlobalSection(ExtensibilityGlobals) = postSolution
54 | SolutionGuid = {5D838DCC-759C-4EB1-9DD5-FF87A299A6D5}
55 | EndGlobalSection
56 | EndGlobal
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ImageProcessor
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
14 |
15 | **ImageProcessor is, and will only ever be supported on the .NET Framework running on a Windows OS. Please do not attempt to use with .NET Core or NET 5+**
16 |
17 | ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
18 |
19 | **Imageprocessor** is a lightweight, fluent wrapper around System.Drawing.
20 |
21 | It's fast, extensible, easy to use, comes bundled with some great features and is fully open source.
22 |
23 | For full documentation please see [https://jimbobsquarepants.github.io/ImageProcessor/](https://jimbobsquarepants.github.io/ImageProcessor/)
24 |
25 | ## Roadmap
26 | Focus for the ImageProcessor libraries has switched to desktop only due to the [lack of support for System.Drawing on Windows Services and ASP.NET](https://docs.microsoft.com/en-us/dotnet/api/system.drawing?view=netframework-4.8#remarks). As such, the `ImageProcessor.Web`and accompanying libraries will not be further developed. For an alternative please use [`ImageSharp.Web`](https://github.com/SixLabors/ImageSharp.Web).
27 |
28 | ImageProcessor has been retired. For modern platforms use [`ImageSharp`](https://github.com/SixLabors/ImageSharp)
29 |
30 | ### Latest Releases
31 | | Library | Version |
32 | | :-------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ |
33 | | **ImageProcessor** | [](https://www.nuget.org/packages/ImageProcessor) |
34 | | **ImageProcessor.Plugins.WebP** | [](https://www.nuget.org/packages/ImageProcessor.Plugins.WebP) |
35 |
36 |
37 | ## Documentation
38 |
39 | ImageProcessor's documentation, included in this repo in the gh-pages branch, is built with [Jekyll](http://jekyllrb.com) and publicly hosted on GitHub Pages at For full documentation please see [https://jimbobsquarepants.github.io/ImageProcessor/](https://jimbobsquarepants.github.io/ImageProcessor/). The docs may also be run locally.
40 |
41 | ### Running documentation locally
42 | 1. If necessary, [install Jekyll](http://jekyllrb.com/docs/installation) (requires v2.5.3x).
43 | - **Windows users:** Read [this unofficial guide](https://github.com/juthilo/run-jekyll-on-windows/) to get Jekyll up and running without problems.
44 | 2. From the root `/ImageProcessor` directory, run `jekyll serve` in the command line.
45 | 3. Open in your browser to navigate to your site.
46 | Learn more about using Jekyll by reading its [documentation](http://jekyllrb.com/docs/home/).
47 |
48 | ### The ImageProcessor Team
49 |
50 | Grand High Eternal Dictator
51 | - [James Jackson-South](https://github.com/jimbobsquarepants)
52 |
--------------------------------------------------------------------------------
/src/ImageProcessor.Plugins.WebP/ImageProcessor.Plugins.WebP.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net452
5 | 7.3
6 |
7 |
8 |
9 | bin\Release\net452\ImageProcessor.Plugins.WebP.xml
10 | true
11 |
12 |
13 |
14 | bin\Debug\net452\ImageProcessor.Plugins.WebP.xml
15 | true
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | all
30 | runtime; build; native; contentfiles; analyzers; buildtransitive
31 |
32 |
33 |
34 |
35 | ..\..\ImageProcessor.ruleset
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/ImageProcessor.Plugins.WebP/README.md:
--------------------------------------------------------------------------------
1 | # Build instructions for libwebp.dll
2 |
3 | Download libwebp source via git or through http download.
4 |
5 | In Start Menu, run Visual Studio Tools > Command Prompt.
6 |
7 | Change to the libwebp directory and run
8 |
9 | nmake /f Makefile.vc CFG=release-dynamic RTLIBCFG=dynamic OBJDIR=output
10 |
11 | Repeat with the
12 | Visual Studio x64 Cross Tools Command Prompt
13 |
14 |
15 | Copy to x86 and x64 directories from /output/
16 |
17 | To verify p/invokes have not changed:
18 |
19 | Review the following history logs for changes since the last release:
20 |
21 | http://git.chromium.org/gitweb/?p=webm/libwebp.git;a=history;f=src/webp/types.h;hb=HEAD
22 | http://git.chromium.org/gitweb/?p=webm/libwebp.git;a=history;f=src/webp/encode.h;hb=HEAD
23 | http://git.chromium.org/gitweb/?p=webm/libwebp.git;a=history;f=src/webp/decode.h;hb=HEAD
24 |
--------------------------------------------------------------------------------
/src/ImageProcessor.Plugins.WebP/Resources/Unmanaged/README.txt:
--------------------------------------------------------------------------------
1 | Build instructions for libwebp.dll
2 | ==================================
3 |
4 | Current version : 1.0.3
5 |
6 | Download libwebp-{version}.tar.gz from the downloads list at http://downloads.webmproject.org/releases/webp
7 | and extract its contents.
8 |
9 | In Start Menu, run Visual Studio Tools>Command Prompt.
10 | C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts\Developer Command Prompt for VS2013
11 |
12 | Change to the libwebp-{version} directory, run:
13 |
14 | nmake /f Makefile.vc CFG=release-dynamic RTLIBCFG=dynamic OBJDIR=output
15 |
16 | Repeat with the x64 Cross Tools Command Prompt.
17 | C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts\VS2013 x64 Cross Tools Command Prompt
18 |
19 | Copy to x86 and x64 directories from /output/bin/
20 |
21 | To verify p/invokes have not changed:
22 |
23 | Review the following history logs for changes since the last release:
24 |
25 | http://git.chromium.org/gitweb/?p=webm/libwebp.git;a=history;f=src/webp/types.h;hb=HEAD
26 | http://git.chromium.org/gitweb/?p=webm/libwebp.git;a=history;f=src/webp/encode.h;hb=HEAD
27 | http://git.chromium.org/gitweb/?p=webm/libwebp.git;a=history;f=src/webp/decode.h;hb=HEAD
28 |
--------------------------------------------------------------------------------
/src/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x64/libwebp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/95f44a217d22642ab7aaa2940286bf4c5f43c2ee/src/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x64/libwebp.dll
--------------------------------------------------------------------------------
/src/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x86/libwebp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/95f44a217d22642ab7aaa2940286bf4c5f43c2ee/src/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x86/libwebp.dll
--------------------------------------------------------------------------------
/src/ImageProcessor/Bgra32.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Runtime.InteropServices;
7 |
8 | namespace ImageProcessor
9 | {
10 | ///
11 | /// Structure that defines a 32 bits per pixel Bgra color. Used for pixel manipulation not for color conversion.
12 | ///
13 | [StructLayout(LayoutKind.Explicit)]
14 | public struct Bgra32 : IEquatable
15 | {
16 | ///
17 | /// Holds the blue component of the color.
18 | ///
19 | [FieldOffset(0)]
20 | public byte B;
21 |
22 | ///
23 | /// Holds the green component of the color.
24 | ///
25 | [FieldOffset(1)]
26 | public byte G;
27 |
28 | ///
29 | /// Holds the red component of the color.
30 | ///
31 | [FieldOffset(2)]
32 | public byte R;
33 |
34 | ///
35 | /// Holds the alpha component of the color.
36 | ///
37 | [FieldOffset(3)]
38 | public byte A;
39 |
40 | ///
41 | /// Permits the color32 to be treated as a 32 bit integer.
42 | ///
43 | [FieldOffset(0)]
44 | public int Argb;
45 |
46 | ///
47 | /// Initializes a new instance of the struct.
48 | ///
49 | /// The alpha component.
50 | /// The red component.
51 | /// The green component.
52 | /// The blue component.
53 | public Bgra32(byte alpha, byte red, byte green, byte blue)
54 | : this()
55 | {
56 | this.A = alpha;
57 | this.R = red;
58 | this.G = green;
59 | this.B = blue;
60 | }
61 |
62 | ///
63 | /// Initializes a new instance of the struct.
64 | ///
65 | /// The combined color components.
66 | public Bgra32(int argb)
67 | : this() => this.Argb = argb;
68 |
69 | ///
70 | /// Gets the color for this Color32 object.
71 | ///
72 | public Color Color => Color.FromArgb(this.A, this.R, this.G, this.B);
73 |
74 | ///
75 | /// Indicates whether this instance and a specified are equal.
76 | ///
77 | /// The instance on the left hand of the operator.
78 | /// The instance on the right hand of the operator.
79 | /// The .
80 | public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right);
81 |
82 | ///
83 | /// Indicates whether this instance and a specified are not equal.
84 | ///
85 | /// The instance on the left hand of the operator.
86 | /// The instance on the right hand of the operator.
87 | /// The .
88 | public static bool operator !=(Bgra32 left, Bgra32 right) => !(left == right);
89 |
90 | ///
91 | public override bool Equals(object obj) => obj is Bgra32 color && this.Equals(color);
92 |
93 | ///
94 | public bool Equals(Bgra32 other) => this.Argb.Equals(other.Argb);
95 |
96 | ///
97 | public override int GetHashCode() => this.GetHashCode(this);
98 |
99 | private int GetHashCode(Bgra32 color)
100 | {
101 | unchecked
102 | {
103 | int hashCode = color.B.GetHashCode();
104 | hashCode = (hashCode * 397) ^ color.G.GetHashCode();
105 | hashCode = (hashCode * 397) ^ color.R.GetHashCode();
106 | return (hashCode * 397) ^ color.A.GetHashCode();
107 | }
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.Serialization;
6 |
7 | namespace ImageProcessor
8 | {
9 | ///
10 | /// The exception that is thrown when loading the supported image format types has failed.
11 | ///
12 | [Serializable]
13 | public sealed class ImageFormatException : Exception
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The message that describes the error.
19 | public ImageFormatException(string message)
20 | : base(message)
21 | {
22 | }
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// The error message that explains the reason for the exception.
28 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
29 | public ImageFormatException(string message, Exception innerException)
30 | : base(message, innerException)
31 | {
32 | }
33 |
34 | ///
35 | /// Initializes a new instance of the class.
36 | ///
37 | public ImageFormatException()
38 | {
39 | }
40 |
41 | ///
42 | /// Initializes a new instance of the class with serialized data.
43 | ///
44 | /// The that holds the serialized object data about the exception being thrown.
45 | /// The that contains contextual information about the source or destination.
46 | /// The parameter is null.
47 | /// The class name is null or is zero (0).
48 | private ImageFormatException(SerializationInfo info, StreamingContext context)
49 | : base(info, context)
50 | {
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.Serialization;
6 |
7 | namespace ImageProcessor
8 | {
9 | ///
10 | /// The exception that is thrown when processing an image has failed.
11 | ///
12 | [Serializable]
13 | public sealed class ImageProcessingException : Exception
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The message that describes the error.
19 | public ImageProcessingException(string message)
20 | : base(message)
21 | {
22 | }
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// The error message that explains the reason for the exception.
28 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
29 | public ImageProcessingException(string message, Exception innerException)
30 | : base(message, innerException)
31 | {
32 | }
33 |
34 | ///
35 | /// Initializes a new instance of the class.
36 | ///
37 | public ImageProcessingException()
38 | {
39 | }
40 |
41 | ///
42 | /// Initializes a new instance of the class with serialized data.
43 | ///
44 | /// The that holds the serialized object data about the exception being thrown.
45 | /// The that contains contextual information about the source or destination.
46 | /// The parameter is null.
47 | /// The class name is null or is zero (0).
48 | private ImageProcessingException(SerializationInfo info, StreamingContext context)
49 | : base(info, context)
50 | {
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Exceptions/Logging/DefaultLogger.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Diagnostics;
6 | using System.Runtime.CompilerServices;
7 |
8 | namespace ImageProcessor
9 | {
10 | ///
11 | /// The default logger which logs messages to the trace listeners.
12 | ///
13 | ///
14 | public class DefaultLogger : ILogger
15 | {
16 | ///
17 | /// Logs the specified message.
18 | ///
19 | /// The type calling the logger.
20 | /// The message to log.
21 | /// The property or method name calling the log.
22 | /// The line number where the method is called.
23 | public void Log(string text, [CallerMemberName] string callerName = null, [CallerLineNumber] int lineNumber = 0) => this.LogInternal(typeof(T), text, callerName, lineNumber);
24 |
25 | ///
26 | /// Logs the specified message.
27 | ///
28 | /// The type calling the logger.
29 | /// The message to log.
30 | /// The property or method name calling the log.
31 | /// The line number where the method is called.
32 | public void Log(Type type, string text, [CallerMemberName] string callerName = null, [CallerLineNumber] int lineNumber = 0) => this.LogInternal(type, text, callerName, lineNumber);
33 |
34 | ///
35 | /// Logs the specified message.
36 | ///
37 | /// The type calling the logger.
38 | /// The message to log.
39 | /// The property or method name calling the log.
40 | /// The line number where the method is called.
41 | [Conditional("TRACE")]
42 | private void LogInternal(Type type, string text, string callerName = null, int lineNumber = 0)
43 | {
44 | string message = string.Format("{0} - {1}: {2} {3}:{4}", DateTime.UtcNow.ToString("s"), type.Name, callerName, lineNumber, text);
45 |
46 | Trace.WriteLine(message);
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Exceptions/Logging/ILogger.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace ImageProcessor
8 | {
9 | ///
10 | /// Encapsulates properties and methods for logging messages.
11 | ///
12 | public interface ILogger
13 | {
14 | ///
15 | /// Logs the specified message.
16 | ///
17 | /// The type calling the logger.
18 | /// The message to log.
19 | /// The property or method name calling the log.
20 | /// The line number where the method is called.
21 | void Log(string text, [CallerMemberName] string callerName = null, [CallerLineNumber] int lineNumber = 0);
22 |
23 | ///
24 | /// Logs the specified message.
25 | ///
26 | /// The type calling the logger.
27 | /// The message to log.
28 | /// The property or method name calling the log.
29 | /// The line number where the method is called.
30 | void Log(Type type, string text, [CallerMemberName] string callerName = null, [CallerLineNumber] int lineNumber = 0);
31 | }
32 | }
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Exceptions/QuantizationException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.Serialization;
6 |
7 | namespace ImageProcessor
8 | {
9 | ///
10 | /// The exception that is thrown when quantizing an image has failed.
11 | ///
12 | [Serializable]
13 | public class QuantizationException : Exception
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | ///
19 | /// The message.
20 | ///
21 | public QuantizationException(string message)
22 | : base(message)
23 | {
24 | }
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// The error message that explains the reason for the exception.
30 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
31 | public QuantizationException(string message, Exception innerException)
32 | : base(message, innerException)
33 | {
34 | }
35 |
36 | ///
37 | /// Initializes a new instance of the class.
38 | ///
39 | public QuantizationException()
40 | {
41 | }
42 |
43 | ///
44 | /// Initializes a new instance of the class with serialized data.
45 | ///
46 | /// The that holds the serialized object data about the exception being thrown.
47 | /// The that contains contextual information about the source or destination.
48 | /// The parameter is null.
49 | /// The class name is null or is zero (0).
50 | private QuantizationException(SerializationInfo info, StreamingContext context)
51 | : base(info, context)
52 | {
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Reflection;
9 | using System.Text;
10 |
11 | namespace ImageProcessor
12 | {
13 | ///
14 | /// Encapsulates a series of time saving extension methods to the class.
15 | ///
16 | public static class AssemblyExtensions
17 | {
18 | ///
19 | /// Gets a collection of loadable types from the given assembly.
20 | /// Adapted from .
21 | ///
22 | /// The to load the types from.
23 | ///
24 | /// The loadable .
25 | ///
26 | public static IEnumerable GetLoadableTypes(this Assembly assembly)
27 | {
28 | if (assembly is null)
29 | {
30 | throw new ArgumentNullException(nameof(assembly));
31 | }
32 |
33 | try
34 | {
35 | return assembly.GetTypes();
36 | }
37 | catch (ReflectionTypeLoadException ex)
38 | {
39 | return ex.Types.Where(t => t != null);
40 | }
41 | }
42 |
43 | ///
44 | /// Converts an assembly resource into a string.
45 | ///
46 | /// The to load the strings from.
47 | /// The resource.
48 | /// The character encoding to return the resource in.
49 | ///
50 | /// The .
51 | ///
52 | public static string GetResourceAsString(this Assembly assembly, string resource, Encoding encoding = null)
53 | {
54 | encoding = encoding ?? Encoding.UTF8;
55 |
56 | using (var ms = new MemoryStream())
57 | {
58 | using (Stream manifestResourceStream = assembly.GetManifestResourceStream(resource))
59 | {
60 | manifestResourceStream?.CopyTo(ms);
61 | }
62 |
63 | return encoding.GetString(ms.GetBuffer()).Replace('\0', ' ').Trim();
64 | }
65 | }
66 |
67 | ///
68 | /// Returns the identifying the file used to load the assembly.
69 | ///
70 | /// The to get the name from.
71 | /// The .
72 | public static FileInfo GetAssemblyFile(this Assembly assembly)
73 | {
74 | string codeBase = assembly.CodeBase;
75 | var uri = new Uri(codeBase);
76 | string path = uri.LocalPath;
77 | return new FileInfo(path);
78 | }
79 |
80 | ///
81 | /// Returns the identifying the file used to load the assembly.
82 | ///
83 | /// The to get the name from.
84 | /// The .
85 | public static FileInfo GetAssemblyFile(this AssemblyName assemblyName)
86 | {
87 | string codeBase = assemblyName.CodeBase;
88 | var uri = new Uri(codeBase);
89 | string path = uri.LocalPath;
90 | return new FileInfo(path);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Extensions/DoubleExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 |
6 | namespace ImageProcessor
7 | {
8 | ///
9 | /// Encapsulates a series of time saving extension methods to the class.
10 | ///
11 | public static class DoubleExtensions
12 | {
13 | ///
14 | /// Converts an value into a valid .
15 | ///
16 | /// If the value given is less than 0 or greater than 255, the value will be constrained into
17 | /// those restricted ranges.
18 | ///
19 | ///
20 | /// The to convert.
21 | /// The .
22 | public static byte ToByte(this double value) => Convert.ToByte(NumberUtilities.Clamp(value, 0, 255));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Extensions/ImageExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 | using System.Linq;
7 | using ImageProcessor.Configuration;
8 | using ImageProcessor.Formats;
9 |
10 | namespace ImageProcessor
11 | {
12 | ///
13 | /// Extension methods for the type.
14 | ///
15 | public static class ImageExtensions
16 | {
17 | ///
18 | /// Creates a deep copy of the source image.
19 | ///
20 | /// The source image.
21 | /// The .
22 | public static Bitmap DeepClone(this Image source) => DeepClone(source, source.PixelFormat);
23 |
24 | ///
25 | /// Creates a deep copy of the source image.
26 | ///
27 | /// The source image.
28 | /// The target pixel format.
29 | /// The .
30 | public static Bitmap DeepClone(this Image source, PixelFormat targetFormat)
31 | => DeepClone(source, targetFormat, FrameProcessingMode.All);
32 |
33 | ///
34 | /// Creates a deep copy of the source image.
35 | ///
36 | /// The source image.
37 | /// The target pixel format.
38 | /// The frame processing mode.
39 | /// The .
40 | public static Bitmap DeepClone(
41 | this Image source,
42 | PixelFormat targetFormat,
43 | FrameProcessingMode frameProcessingMode)
44 | => DeepClone(source, targetFormat, frameProcessingMode, true);
45 |
46 | ///
47 | /// Creates a deep copy of the source image.
48 | ///
49 | /// The source image.
50 | /// The target pixel format.
51 | /// The frame processing mode.
52 | /// Whether to preserve metadata.
53 | /// The .
54 | public static Bitmap DeepClone(
55 | this Image source,
56 | PixelFormat targetFormat,
57 | FrameProcessingMode frameProcessingMode,
58 | bool preserveMetaData)
59 | {
60 | IImageFormat format = ImageProcessorBootstrapper.Instance.ImageFormats
61 | .FirstOrDefault(x => x.ImageFormat.Equals(source.RawFormat));
62 |
63 | if (format is null)
64 | {
65 | format = ImageProcessorBootstrapper.Instance.ImageFormats
66 | .First(x => x is BitmapFormat);
67 | }
68 |
69 | return format.DeepClone(source, targetFormat, frameProcessingMode, preserveMetaData);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Extensions/IntegerExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor
5 | {
6 | ///
7 | /// Encapsulates a series of time saving extension methods to the class.
8 | ///
9 | public static class IntegerExtensions
10 | {
11 | ///
12 | /// Converts an value into a valid .
13 | ///
14 | /// If the value given is less than 0 or greater than 255, the value will be constrained into
15 | /// those restricted ranges.
16 | ///
17 | ///
18 | /// The to convert.
19 | /// The .
20 | public static byte ToByte(this int value) => (byte)NumberUtilities.Clamp(value, 0, 255);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Extensions/StreamExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Buffers;
6 | using System.IO;
7 |
8 | namespace ImageProcessor
9 | {
10 | internal static class StreamExtensions
11 | {
12 | #if !SUPPORTS_SPAN_STREAM
13 | // This is a port of the CoreFX implementation and is MIT Licensed:
14 | // https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L742
15 | public static int Read(this Stream stream, Span buffer)
16 | {
17 | // This uses ArrayPool.Shared, rather than taking a MemoryAllocator,
18 | // in order to match the signature of the framework method that exists in
19 | // .NET Core.
20 | byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Length);
21 | try
22 | {
23 | int numRead = stream.Read(sharedBuffer, 0, buffer.Length);
24 | if ((uint)numRead > (uint)buffer.Length)
25 | {
26 | throw new IOException("Stream was too long.");
27 | }
28 |
29 | new Span(sharedBuffer, 0, numRead).CopyTo(buffer);
30 | return numRead;
31 | }
32 | finally
33 | {
34 | ArrayPool.Shared.Return(sharedBuffer);
35 | }
36 | }
37 |
38 | // This is a port of the CoreFX implementation and is MIT Licensed:
39 | // https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L775
40 | public static void Write(this Stream stream, ReadOnlySpan buffer)
41 | {
42 | // This uses ArrayPool.Shared, rather than taking a MemoryAllocator,
43 | // in order to match the signature of the framework method that exists in
44 | // .NET Core.
45 | byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Length);
46 | try
47 | {
48 | buffer.CopyTo(sharedBuffer);
49 | stream.Write(sharedBuffer, 0, buffer.Length);
50 | }
51 | finally
52 | {
53 | ArrayPool.Shared.Return(sharedBuffer);
54 | }
55 | }
56 | #endif
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Helpers/BigEndianBitConverter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor
5 | {
6 | ///
7 | /// Implementation of EndianBitConverter which converts to/from big-endian byte arrays.
8 | ///
9 | /// Adapted from Miscellaneous Utility Library .
10 | ///
11 | ///
12 | internal sealed class BigEndianBitConverter : EndianBitConverter
13 | {
14 | ///
15 | public override Endianness Endianness => Endianness.BigEndian;
16 |
17 | ///
18 | public override bool IsLittleEndian() => false;
19 |
20 | ///
21 | protected internal override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
22 | {
23 | int endOffset = index + bytes - 1;
24 | for (int i = 0; i < bytes; i++)
25 | {
26 | buffer[endOffset - i] = unchecked((byte)(value & 0xff));
27 | value >>= 8;
28 | }
29 | }
30 |
31 | ///
32 | protected internal override long FromBytes(byte[] value, int startIndex, int bytesToConvert)
33 | {
34 | long ret = 0;
35 | for (int i = 0; i < bytesToConvert; i++)
36 | {
37 | ret = unchecked((ret << 8) | value[startIndex + i]);
38 | }
39 |
40 | return ret;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Helpers/ComputerArchitectureInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 |
6 | namespace ImageProcessor
7 | {
8 | ///
9 | /// Encapsulates methods that provide information about the current computer architecture.
10 | ///
11 | public class ComputerArchitectureInfo : IComputerArchitectureInfo
12 | {
13 | ///
14 | /// Returns a value indicating whether the current computer architecture is little endian.
15 | ///
16 | /// The .
17 | public bool IsLittleEndian() => BitConverter.IsLittleEndian;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Helpers/Endianness.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor
5 | {
6 | ///
7 | /// Enumerates the Endianness of a converter.
8 | ///
9 | internal enum Endianness
10 | {
11 | ///
12 | /// Little endian - least significant byte first.
13 | ///
14 | LittleEndian,
15 |
16 | ///
17 | /// Big endian - most significant byte first.
18 | ///
19 | BigEndian
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Helpers/EnumerableUtilities.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | namespace ImageProcessor
8 | {
9 | ///
10 | /// Encapsulates a series of time saving extension methods to the interface.
11 | ///
12 | public static class EnumerableUtilities
13 | {
14 | ///
15 | /// Generates a sequence of integral numbers within a specified range.
16 | ///
17 | /// The start index, inclusive.
18 | /// The end index, exclusive.
19 | /// The incremental step.
20 | ///
21 | /// The that contains a range of sequential integral numbers.
22 | ///
23 | public static IEnumerable SteppedRange(int fromInclusive, int toExclusive, int step)
24 | {
25 | // Borrowed from Enumerable.Range
26 | long num = (fromInclusive + toExclusive) - 1L;
27 |
28 | if ((toExclusive < 0) || (num > 0x7fffffffL))
29 | {
30 | throw new ArgumentOutOfRangeException(nameof(toExclusive));
31 | }
32 |
33 | return SteppedRange(fromInclusive, i => i < toExclusive, step);
34 | }
35 |
36 | ///
37 | /// Generates a sequence of integral numbers within a specified range.
38 | ///
39 | /// The start index, inclusive.
40 | ///
41 | /// A method that has one parameter and returns a calculating the end index.
42 | ///
43 | /// The incremental step.
44 | ///
45 | /// The that contains a range of sequential integral numbers.
46 | ///
47 | public static IEnumerable SteppedRange(int fromInclusive, Func toDelegate, int step)
48 | => RangeIterator(fromInclusive, toDelegate, step);
49 |
50 | ///
51 | /// Generates a sequence of integral numbers within a specified range.
52 | ///
53 | /// The start index, inclusive.
54 | ///
55 | /// A method that has one parameter and returns a calculating the end index.
56 | ///
57 | /// The incremental step.
58 | ///
59 | /// The that contains a range of sequential integral numbers.
60 | ///
61 | private static IEnumerable RangeIterator(int fromInclusive, Func toDelegate, int step)
62 | {
63 | int i = fromInclusive;
64 | while (toDelegate(i))
65 | {
66 | yield return i;
67 | i += step;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Helpers/GeometryUtilities.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace ImageProcessor
8 | {
9 | ///
10 | /// Utility class for common geometric functions.
11 | ///
12 | public static class GeometryUtilities
13 | {
14 | ///
15 | /// Converts a degree (360-periodic) angle to a radian (2*Pi-periodic) angle.
16 | ///
17 | /// The angle in degrees.
18 | ///
19 | /// The representing the degree as radians.
20 | ///
21 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 | public static float DegreeToRadian(float degree) => degree * (float)(Math.PI / 180F);
23 |
24 | ///
25 | /// Converts a radian (2*Pi-periodic) angle to a degree (360-periodic) angle.
26 | ///
27 | /// The angle in radians.
28 | ///
29 | /// The representing the degree as radians.
30 | ///
31 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
32 | public static float RadianToDegree(float radian) => radian / (float)(Math.PI / 180F);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Helpers/IComputerArchitectureInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor
5 | {
6 | ///
7 | /// Encapsulates methods that provide information about the current computer architecture.
8 | ///
9 | public interface IComputerArchitectureInfo
10 | {
11 | ///
12 | /// Returns a value indicating whether the current computer architecture is little endian.
13 | ///
14 | /// The .
15 | bool IsLittleEndian();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Common/Helpers/LittleEndianBitConverter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor
5 | {
6 | ///
7 | /// Implementation of EndianBitConverter which converts to/from little-endian byte arrays.
8 | ///
9 | /// Adapted from Miscellaneous Utility Library .
10 | ///
11 | ///
12 | internal sealed class LittleEndianBitConverter : EndianBitConverter
13 | {
14 | ///
15 | public override Endianness Endianness => Endianness.LittleEndian;
16 |
17 | ///
18 | public override bool IsLittleEndian() => true;
19 |
20 | ///
21 | protected internal override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
22 | {
23 | for (int i = 0; i < bytes; i++)
24 | {
25 | buffer[i + index] = unchecked((byte)(value & 0xff));
26 | value >>= 8;
27 | }
28 | }
29 |
30 | ///
31 | protected internal override long FromBytes(byte[] value, int startIndex, int bytesToConvert)
32 | {
33 | long ret = 0;
34 | for (int i = 0; i < bytesToConvert; i++)
35 | {
36 | ret = unchecked((ret << 8) | value[startIndex + bytesToConvert - 1 - i]);
37 | }
38 |
39 | return ret;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using ImageProcessor.Formats;
8 |
9 | namespace ImageProcessor.Configuration
10 | {
11 | ///
12 | /// The bootstrapper containing initialization code for extending ImageProcessor.
13 | ///
14 | public sealed class ImageProcessorBootstrapper
15 | {
16 | ///
17 | /// A new instance Initializes a new instance of the class.
18 | /// with lazy initialization.
19 | ///
20 | private static readonly Lazy Lazy =
21 | new Lazy(() => new ImageProcessorBootstrapper());
22 |
23 | ///
24 | /// Prevents a default instance of the class from being created.
25 | ///
26 | private ImageProcessorBootstrapper() => this.LoadSupportedImageFormats();
27 |
28 | ///
29 | /// Gets the current instance of the class.
30 | ///
31 | public static ImageProcessorBootstrapper Instance => Lazy.Value;
32 |
33 | ///
34 | /// Gets the supported image formats.
35 | ///
36 | public IReadOnlyCollection ImageFormats { get; private set; }
37 |
38 | ///
39 | /// Gets the currently installed logger.
40 | ///
41 | public ILogger Logger { get; private set; } = new DefaultLogger();
42 |
43 | ///
44 | /// Gets the native binary factory for registering embedded (unmanaged) binaries.
45 | ///
46 | public NativeBinaryFactory NativeBinaryFactory { get; } = new NativeBinaryFactory();
47 |
48 | ///
49 | /// Adds the given image formats to the supported format collection.
50 | ///
51 | /// The instances to add.
52 | public void AddImageFormats(params IImageFormat[] formats)
53 | {
54 | var currentFormats = (List)this.ImageFormats;
55 |
56 | foreach (IImageFormat format in formats)
57 | {
58 | if (currentFormats.Any(x => x.Equals(format)))
59 | {
60 | continue;
61 | }
62 |
63 | currentFormats.Add(format);
64 | }
65 | }
66 |
67 | ///
68 | /// Allows the setting of the default logger. Useful for when
69 | /// the type finder fails to dynamically add the custom logger implementation.
70 | ///
71 | /// The logger to use.
72 | public void SetLogger(ILogger logger) => this.Logger = logger;
73 |
74 | ///
75 | /// Creates a collection of supported image formats that ImageProcessor can run.
76 | ///
77 | private void LoadSupportedImageFormats()
78 | {
79 | this.ImageFormats = new List
80 | {
81 | new BitmapFormat(),
82 | new GifFormat(),
83 | new JpegFormat(),
84 | new PngFormat(),
85 | new TiffFormat()
86 | };
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Configuration/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace ImageProcessor.Configuration
8 | {
9 | ///
10 | /// Provides access to unmanaged native methods.
11 | ///
12 | internal static class NativeMethods
13 | {
14 | ///
15 | /// Loads the specified module into the address space of the calling process.
16 | /// The specified module may cause other modules to be loaded.
17 | ///
18 | ///
19 | /// The name of the module. This can be either a library module or
20 | /// an executable module.
21 | ///
22 | /// If the function succeeds, the return value is a handle to the module; otherwise null.
23 | [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
24 | public static extern IntPtr LoadLibrary(string libname);
25 |
26 | ///
27 | /// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count.
28 | /// When the reference count reaches zero, the module is unloaded from the address space of the calling
29 | /// process and the handle is no longer valid.
30 | ///
31 | /// A handle to the loaded library module.
32 | /// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle.
33 | /// If the function succeeds, the return value is nonzero; otherwise zero.
34 | [DllImport("kernel32", SetLastError = true)]
35 | public static extern bool FreeLibrary(IntPtr hModule);
36 |
37 | ///
38 | /// Loads the specified module into the address space of the calling process.
39 | /// The specified module may cause other modules to be loaded.
40 | ///
41 | ///
42 | /// The name of the module. This can be either a library module or
43 | /// an executable module.
44 | ///
45 | ///
46 | /// The flag indicating whether to load the library immediately or lazily.
47 | ///
48 | ///
49 | /// If the function succeeds, the return value is a handle to the module; otherwise null.
50 | ///
51 | [DllImport("libdl")]
52 | #pragma warning disable IDE1006 // Naming Styles
53 | public static extern IntPtr dlopen(string libname, int flags);
54 | #pragma warning restore IDE1006 // Naming Styles
55 |
56 | ///
57 | /// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count.
58 | /// When the reference count reaches zero, the module is unloaded from the address space of the calling
59 | /// process and the handle is no longer valid.
60 | ///
61 | /// A handle to the loaded library module.
62 | /// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle.
63 | /// If the function succeeds, the return value is nonzero; otherwise zero.
64 | [DllImport("libdl")]
65 | #pragma warning disable IDE1006 // Naming Styles
66 | public static extern int dlclose(IntPtr hModule);
67 | #pragma warning restore IDE1006 // Naming Styles
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/BitDepth.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Formats
5 | {
6 | ///
7 | /// Provides enumeration for the available bit depths.
8 | ///
9 | public enum BitDepth : long
10 | {
11 | ///
12 | /// 1 bit per pixel
13 | ///
14 | Bit1 = 1L,
15 |
16 | ///
17 | /// 4 bits per pixel
18 | ///
19 | Bit4 = 4L,
20 |
21 | ///
22 | /// 8 bits per pixel
23 | ///
24 | Bit8 = 8L,
25 |
26 | ///
27 | /// 16 bits per pixel
28 | ///
29 | Bit16 = 16L,
30 |
31 | ///
32 | /// 24 bits per pixel
33 | ///
34 | Bit24 = 24L,
35 |
36 | ///
37 | /// 32 bits per pixel
38 | ///
39 | Bit32 = 32L
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/BitmapFormat.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 | using System.IO;
7 | using System.Text;
8 |
9 | namespace ImageProcessor.Formats
10 | {
11 | ///
12 | /// Provides the necessary information to support bitmap images.
13 | ///
14 | public sealed class BitmapFormat : FormatBase
15 | {
16 | ///
17 | public override byte[][] FileHeaders { get; } = new[]
18 | {
19 | Encoding.ASCII.GetBytes("BM")
20 | };
21 |
22 | ///
23 | public override string[] FileExtensions { get; } = new[]
24 | {
25 | "bmp"
26 | };
27 |
28 | ///
29 | public override string MimeType { get; } = "image/bmp";
30 |
31 | ///
32 | public override ImageFormat ImageFormat { get; } = ImageFormat.Bmp;
33 |
34 | ///
35 | public override void Save(Stream stream, Image image, BitDepth bitDepth, long quality)
36 | {
37 | switch (bitDepth)
38 | {
39 | case BitDepth.Bit1:
40 | case BitDepth.Bit4:
41 | case BitDepth.Bit8:
42 |
43 | // Save as 8 bit quantized image.
44 | // TODO: Consider allowing 1 and 4 bit quantization.
45 | using (Bitmap quantized = this.Quantizer.Quantize(image))
46 | {
47 | CopyMetadata(image, quantized);
48 | base.Save(stream, quantized, bitDepth, quality);
49 | }
50 |
51 | break;
52 |
53 | default:
54 |
55 | PixelFormat pixelFormat = FormatUtilities.GetPixelFormatForBitDepth(bitDepth);
56 |
57 | if (pixelFormat != image.PixelFormat)
58 | {
59 | using (Image copy = this.DeepClone(image, pixelFormat, FrameProcessingMode.All, true))
60 | {
61 | base.Save(stream, copy, bitDepth, quality);
62 | }
63 | }
64 | else
65 | {
66 | base.Save(stream, image, bitDepth, quality);
67 | }
68 |
69 | break;
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/GifDecoder.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Drawing.Imaging;
7 | using ImageProcessor.Metadata;
8 |
9 | namespace ImageProcessor.Formats
10 | {
11 | ///
12 | /// Allows the decoding of gifs into individual frames.
13 | ///
14 | public class GifDecoder
15 | {
16 | private readonly Image image;
17 | private readonly byte[] times = new byte[4];
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | ///
23 | /// The to decode.
24 | ///
25 | public GifDecoder(Image image)
26 | : this(image, FrameProcessingMode.All)
27 | {
28 | }
29 |
30 | ///
31 | /// Initializes a new instance of the class.
32 | ///
33 | /// The image to decode.
34 | /// The frame processing mode.
35 | public GifDecoder(Image image, FrameProcessingMode frameProcessingMode)
36 | {
37 | this.image = image;
38 |
39 | if (FormatUtilities.IsAnimated(image) && frameProcessingMode == FrameProcessingMode.All)
40 | {
41 | this.IsAnimated = true;
42 | this.FrameCount = image.GetFrameCount(FrameDimension.Time);
43 | const int LoopCount = (int)ExifPropertyTag.LoopCount;
44 | const int FrameDelay = (int)ExifPropertyTag.FrameDelay;
45 |
46 | // Loop info is stored at byte 20737. Default to infinite loop if not found.
47 | this.LoopCount = Array.IndexOf(image.PropertyIdList, LoopCount) != -1
48 | ? BitConverter.ToInt16(image.GetPropertyItem(LoopCount).Value, 0)
49 | : 0;
50 |
51 | // Get the times stored in the gif. Default to 0 if not found.
52 | if (Array.IndexOf(this.image.PropertyIdList, FrameDelay) != -1)
53 | {
54 | this.times = this.image.GetPropertyItem(FrameDelay).Value;
55 | }
56 | }
57 | else
58 | {
59 | this.FrameCount = 1;
60 | }
61 | }
62 |
63 | ///
64 | /// Gets the input image.
65 | ///
66 | public Image Image { get; }
67 |
68 | ///
69 | /// Gets a value indicating whether the image is animated.
70 | ///
71 | public bool IsAnimated { get; }
72 |
73 | ///
74 | /// Gets the loop count.
75 | ///
76 | public int LoopCount { get; }
77 |
78 | ///
79 | /// Gets the frame count.
80 | ///
81 | public int FrameCount { get; }
82 |
83 | ///
84 | /// Gets the frame at the specified index.
85 | ///
86 | /// Image frames are returned in format to allow processing
87 | /// using the canvas.
88 | ///
89 | ///
90 | /// The index.
91 | ///
92 | /// The .
93 | ///
94 | public GifFrame GetFrame(int index)
95 | {
96 | // Convert each 4-byte chunk into an integer.
97 | // GDI returns a single array with all delays, while Mono returns a different array for each frame.
98 | var delay = TimeSpan.FromMilliseconds(BitConverter.ToInt32(this.times, (4 * index) % this.times.Length) * 10);
99 |
100 | // Find the frame
101 | this.image.SelectActiveFrame(FrameDimension.Time, index);
102 |
103 | var frame = new GifFrame(this.image, delay);
104 |
105 | // Reset the image
106 | this.image.SelectActiveFrame(FrameDimension.Time, 0);
107 |
108 | return frame;
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/GifFormat.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Drawing.Imaging;
7 | using System.IO;
8 | using System.Text;
9 |
10 | namespace ImageProcessor.Formats
11 | {
12 | ///
13 | /// Provides the necessary information to support gif images.
14 | ///
15 | public sealed class GifFormat : FormatBase
16 | {
17 | ///
18 | public override byte[][] FileHeaders { get; } = new[] { Encoding.ASCII.GetBytes("GIF") };
19 |
20 | ///
21 | public override string[] FileExtensions { get; } = new[] { "gif" };
22 |
23 | ///
24 | public override string MimeType { get; } = "image/gif";
25 |
26 | ///
27 | public override ImageFormat ImageFormat { get; } = ImageFormat.Gif;
28 |
29 | ///
30 | public override Image ApplyProcessor(T processor, ImageFactory factory)
31 | {
32 | var decoder = new GifDecoder(factory.Image, factory.FrameProcessingMode);
33 | var encoder = new GifEncoder(this.Quantizer, decoder.LoopCount);
34 |
35 | for (int i = 0; i < decoder.FrameCount; i++)
36 | {
37 | GifFrame frame = null;
38 | try
39 | {
40 | // Frame images are already a copy so we don't have to copy again for processing.
41 | frame = decoder.GetFrame(i);
42 | processor.ProcessImageFrame(factory, frame.Image);
43 | encoder.EncodeFrame(frame);
44 | }
45 | catch (Exception ex)
46 | {
47 | throw new ImageProcessingException("Error processing image with " + typeof(T).Name, ex);
48 | }
49 | finally
50 | {
51 | frame?.Dispose();
52 | }
53 | }
54 |
55 | return encoder.Encode();
56 | }
57 |
58 | ///
59 | public override Bitmap DeepClone(Image source, PixelFormat targetFormat, FrameProcessingMode frameProcessingMode, bool preserveMetaData)
60 | {
61 | var decoder = new GifDecoder(source, frameProcessingMode);
62 | var encoder = new GifEncoder(this.Quantizer, decoder.LoopCount);
63 |
64 | for (int i = 0; i < decoder.FrameCount; i++)
65 | {
66 | using (GifFrame frame = decoder.GetFrame(i))
67 | {
68 | encoder.EncodeFrame(frame);
69 | }
70 | }
71 |
72 | Image copy = encoder.Encode();
73 |
74 | if (preserveMetaData)
75 | {
76 | CopyMetadata(source, copy);
77 | }
78 |
79 | return (Bitmap)copy;
80 | }
81 |
82 | ///
83 | public override void Save(Stream stream, Image image, BitDepth bitDepth, long quality)
84 | {
85 | // Never use default save for gifs. It's terrible.
86 | // BitDepth is ignored here since we always produce 8 bit images.
87 | var decoder = new GifDecoder(image, FrameProcessingMode.All);
88 | var encoder = new GifEncoder(this.Quantizer, decoder.LoopCount);
89 |
90 | for (int i = 0; i < decoder.FrameCount; i++)
91 | {
92 | using (GifFrame frame = decoder.GetFrame(i))
93 | {
94 | encoder.EncodeFrame(frame);
95 | }
96 | }
97 |
98 | encoder.EncodeToStream(stream);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/GifFrame.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Drawing.Imaging;
7 |
8 | namespace ImageProcessor.Formats
9 | {
10 | ///
11 | /// A single gif frame.
12 | ///
13 | public sealed class GifFrame : IDisposable
14 | {
15 | private bool isDisposed;
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// The source image to copy into the new frame.
21 | /// The time, in milliseconds, to wait before animating to the next frame.
22 | public GifFrame(Image source, TimeSpan delay)
23 | : this(source, delay, 0, 0)
24 | {
25 | }
26 |
27 | ///
28 | /// Initializes a new instance of the class.
29 | ///
30 | /// The source image to copy into the new frame.
31 | /// The time, in milliseconds, to wait before animating to the next frame.
32 | /// The frame left position.
33 | /// The frame top position.
34 | public GifFrame(Image source, TimeSpan delay, int x, int y)
35 | {
36 | this.Image = FormatUtilities.DeepCloneImageFrame(source, PixelFormat.Format32bppArgb);
37 | this.Delay = delay;
38 | this.X = x;
39 | this.Y = y;
40 | }
41 |
42 | ///
43 | /// Gets the image, stored in format to allow processing
44 | /// using the canvas.
45 | ///
46 | public Image Image { get; private set; }
47 |
48 | ///
49 | /// Gets the delay in milliseconds.
50 | ///
51 | public TimeSpan Delay { get; }
52 |
53 | ///
54 | /// Gets the left position of the frame.
55 | ///
56 | public int X { get; }
57 |
58 | ///
59 | /// Gets the top position of the frame.
60 | ///
61 | public int Y { get; }
62 |
63 | ///
64 | public void Dispose()
65 | {
66 | if (this.isDisposed)
67 | {
68 | return;
69 | }
70 |
71 | this.Image?.Dispose();
72 | this.Image = null;
73 | this.isDisposed = true;
74 | GC.SuppressFinalize(this);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/IImageFormat.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Drawing.Imaging;
7 | using System.IO;
8 | using ImageProcessor.Processing;
9 | using ImageProcessor.Quantizers;
10 |
11 | namespace ImageProcessor.Formats
12 | {
13 | ///
14 | /// Defines the contract for a supported image format.
15 | ///
16 | public interface IImageFormat : IEquatable
17 | {
18 | ///
19 | /// Gets the file headers.
20 | ///
21 | byte[][] FileHeaders { get; }
22 |
23 | ///
24 | /// Gets the list of file extensions.
25 | ///
26 | string[] FileExtensions { get; }
27 |
28 | ///
29 | /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains.
30 | ///
31 | string MimeType { get; }
32 |
33 | ///
34 | /// Gets the default file extension.
35 | ///
36 | string DefaultExtension { get; }
37 |
38 | ///
39 | /// Gets the file format of the image.
40 | ///
41 | ImageFormat ImageFormat { get; }
42 |
43 | ///
44 | /// Gets the quantizer for reducing the image palette.
45 | ///
46 | IQuantizer Quantizer { get; }
47 |
48 | ///
49 | /// Loads the image to process.
50 | ///
51 | /// The containing the image information.
52 | ///
53 | /// The .
54 | ///
55 | Image Load(Stream stream);
56 |
57 | ///
58 | /// Applies the given processor the current image.
59 | ///
60 | /// The type of .
61 | /// The processor.
62 | /// The factory.
63 | /// The .
64 | /// Thrown if an error occurs during processing.
65 | Image ApplyProcessor(T processor, ImageFactory factory)
66 | where T : IGraphicsProcessor;
67 |
68 | ///
69 | /// Creates a deep copy of the source image.
70 | ///
71 | /// The source image.
72 | /// The target pixel format.
73 | /// The frame processing mode.
74 | /// Whether to preserve metadata.
75 | /// The .
76 | Bitmap DeepClone(Image source, PixelFormat targetFormat, FrameProcessingMode frameProcessingMode, bool preserveMetaData);
77 |
78 | ///
79 | /// Saves the current image to the specified output stream.
80 | ///
81 | /// The to save the image information to.
82 | /// The to save.
83 | /// The color depth in number of bits per pixel to save the image with.
84 | /// The quality, if applicable, to save the image at.
85 | void Save(Stream stream, Image image, BitDepth bitDepth, long quality);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/JpegFormat.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Drawing.Imaging;
7 | using System.IO;
8 | using System.Text;
9 | using Encoder = System.Drawing.Imaging.Encoder;
10 |
11 | namespace ImageProcessor.Formats
12 | {
13 | ///
14 | /// Provides the necessary information to support jpeg images.
15 | ///
16 | public sealed class JpegFormat : FormatBase
17 | {
18 | private ImageCodecInfo imageCodecInfo;
19 |
20 | ///
21 | public override byte[][] FileHeaders { get; } = new[]
22 | {
23 | new byte[] { 0xFF, 0xD8, 0xFF },
24 | Encoding.ASCII.GetBytes("ÿØÿà..JFIF"),
25 | Encoding.ASCII.GetBytes("ÿØÿà..EXIF")
26 | };
27 |
28 | ///
29 | public override string[] FileExtensions { get; } = new[]
30 | {
31 | "jpg", "jpeg", "jfif"
32 | };
33 |
34 | ///
35 | public override string MimeType { get; } = "image/jpeg";
36 |
37 | ///
38 | public override ImageFormat ImageFormat { get; } = ImageFormat.Jpeg;
39 |
40 | ///
41 | public override void Save(Stream stream, Image image, BitDepth bitDepth, long quality)
42 | {
43 | // Jpegs can be saved with different settings to include a quality setting for the JPEG compression.
44 | // This improves output compression and quality.
45 | using (EncoderParameters encoderParameters = GetEncoderParameters(quality))
46 | {
47 | image.Save(stream, this.GetCodecInfo(), encoderParameters);
48 | }
49 | }
50 |
51 | private static EncoderParameters GetEncoderParameters(long quality)
52 | {
53 | return new EncoderParameters(1)
54 | {
55 | // Set the quality.
56 | Param = { [0] = new EncoderParameter(Encoder.Quality, quality) }
57 | };
58 | }
59 |
60 | private ImageCodecInfo GetCodecInfo()
61 | {
62 | return this.imageCodecInfo ?? (this.imageCodecInfo = Array.Find(
63 | ImageCodecInfo.GetImageEncoders(),
64 | ici => ici.MimeType.Equals(this.MimeType, StringComparison.OrdinalIgnoreCase)));
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/PngFormat.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 | using System.IO;
7 | using ImageProcessor.Quantizers;
8 |
9 | namespace ImageProcessor.Formats
10 | {
11 | ///
12 | /// Provides the necessary information to support png images.
13 | ///
14 | public sealed class PngFormat : FormatBase
15 | {
16 | private static readonly byte[][] Identifier = new[]
17 | {
18 | new byte[] { 0x89, 0x50, 0x4E, 0x47 }
19 | };
20 |
21 | private static readonly string[] Extensions = new[]
22 | {
23 | "png"
24 | };
25 |
26 | ///
27 | public override byte[][] FileHeaders => Identifier;
28 |
29 | ///
30 | public override string[] FileExtensions => Extensions;
31 |
32 | ///
33 | public override string MimeType => "image/png";
34 |
35 | ///
36 | public override ImageFormat ImageFormat => ImageFormat.Png;
37 |
38 | ///
39 | public override IQuantizer Quantizer => new WuQuantizer();
40 |
41 | ///
42 | public override void Save(Stream stream, Image image, BitDepth bitDepth, long quality)
43 | {
44 | switch (bitDepth)
45 | {
46 | case BitDepth.Bit1:
47 | case BitDepth.Bit4:
48 | case BitDepth.Bit8:
49 |
50 | // Save as 8 bit quantized image.
51 | // TODO: Consider allowing 1 and 4 bit quantization.
52 | using (Bitmap quantized = this.Quantizer.Quantize(image))
53 | {
54 | CopyMetadata(image, quantized);
55 | base.Save(stream, quantized, bitDepth, quality);
56 | }
57 |
58 | break;
59 |
60 | default:
61 |
62 | PixelFormat pixelFormat = FormatUtilities.GetPixelFormatForBitDepth(bitDepth);
63 |
64 | if (pixelFormat != image.PixelFormat)
65 | {
66 | using (Image copy = this.DeepClone(image, pixelFormat, FrameProcessingMode.All, true))
67 | {
68 | base.Save(stream, copy, bitDepth, quality);
69 | }
70 | }
71 | else
72 | {
73 | base.Save(stream, image, bitDepth, quality);
74 | }
75 |
76 | break;
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Formats/TiffFormat.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Drawing.Imaging;
7 | using System.IO;
8 | using ImageProcessor.Quantizers;
9 |
10 | namespace ImageProcessor.Formats
11 | {
12 | ///
13 | /// Provides the necessary information to support tiff images.
14 | ///
15 | public sealed class TiffFormat : FormatBase
16 | {
17 | private ImageCodecInfo imageCodecInfo;
18 |
19 | ///
20 | public override byte[][] FileHeaders { get; } = new[]
21 | {
22 | new byte[] { 0x49, 0x49, 0x2A, 0x0 },
23 | new byte[] { 0x4D, 0x4D, 0x0, 0x2A }
24 | };
25 |
26 | ///
27 | public override string[] FileExtensions { get; } = new[]
28 | {
29 | "tif", "tiff"
30 | };
31 |
32 | ///
33 | public override string MimeType => "image/tiff";
34 |
35 | ///
36 | public override ImageFormat ImageFormat => ImageFormat.Tiff;
37 |
38 | ///
39 | public override IQuantizer Quantizer { get; } = new OctreeQuantizer();
40 |
41 | ///
42 | public override void Save(Stream stream, Image image, BitDepth bitDepth, long quality)
43 | {
44 | // Tiffs can be saved with different bit depths but throws if we use 16 bits.
45 | if (bitDepth == BitDepth.Bit16)
46 | {
47 | bitDepth = BitDepth.Bit24;
48 | }
49 |
50 | using (EncoderParameters encoderParameters = GetEncoderParameters(bitDepth))
51 | {
52 | switch (bitDepth)
53 | {
54 | case BitDepth.Bit4:
55 | case BitDepth.Bit8:
56 | // Save as 8 bit quantized image.
57 | using (Bitmap quantized = this.Quantizer.Quantize(image))
58 | {
59 | CopyMetadata(image, quantized);
60 | quantized.Save(stream, this.GetCodecInfo(), encoderParameters);
61 | }
62 |
63 | return;
64 |
65 | case BitDepth.Bit24:
66 | case BitDepth.Bit32:
67 |
68 | PixelFormat pixelFormat = FormatUtilities.GetPixelFormatForBitDepth(bitDepth);
69 |
70 | if (pixelFormat != image.PixelFormat)
71 | {
72 | using (Image copy = this.DeepClone(image, pixelFormat, FrameProcessingMode.All, true))
73 | {
74 | copy.Save(stream, this.GetCodecInfo(), encoderParameters);
75 | }
76 | }
77 | else
78 | {
79 | image.Save(stream, this.GetCodecInfo(), encoderParameters);
80 | }
81 |
82 | break;
83 | default:
84 |
85 | // Encoding is handled by the encoding parameters.
86 | image.Save(stream, this.GetCodecInfo(), encoderParameters);
87 | break;
88 | }
89 | }
90 | }
91 |
92 | private static EncoderParameters GetEncoderParameters(BitDepth bitDepth)
93 | {
94 | long colorDepth = (long)bitDepth;
95 |
96 | // CompressionCCITT4 provides 1 bit diffusion.
97 | long compression = (long)(bitDepth == BitDepth.Bit1
98 | ? EncoderValue.CompressionCCITT4
99 | : EncoderValue.CompressionLZW);
100 |
101 | var encoderParameters = new EncoderParameters(2);
102 | encoderParameters.Param[0] = new EncoderParameter(Encoder.Compression, compression);
103 | encoderParameters.Param[1] = new EncoderParameter(Encoder.ColorDepth, colorDepth);
104 |
105 | return encoderParameters;
106 | }
107 |
108 | private ImageCodecInfo GetCodecInfo()
109 | {
110 | return this.imageCodecInfo ?? (this.imageCodecInfo = Array.Find(
111 | ImageCodecInfo.GetImageEncoders(),
112 | ici => ici.MimeType.Equals(this.MimeType, StringComparison.OrdinalIgnoreCase)));
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/ImageProcessor/FrameProcessingMode.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor
5 | {
6 | ///
7 | /// Enumerated frame process modes to apply to multiframe images.
8 | ///
9 | public enum FrameProcessingMode
10 | {
11 | ///
12 | /// Processes and keeps all the frames of a multiframe image.
13 | ///
14 | All,
15 |
16 | ///
17 | /// Processes and keeps only the first frame of a multiframe image.
18 | ///
19 | First
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/ImageProcessor/ImageProcessor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net452
5 | 7.3
6 |
7 |
8 |
9 | bin\Release\net452\ImageProcessor.xml
10 | true
11 |
12 |
13 |
14 | bin\Debug\net452\ImageProcessor.xml
15 | true
16 |
17 |
18 |
19 |
20 | all
21 | runtime; build; native; contentfiles; analyzers; buildtransitive
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ..\..\ImageProcessor.ruleset
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Metadata/ExifBitConverter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Text;
6 |
7 | namespace ImageProcessor.Metadata
8 | {
9 | ///
10 | /// The exif bit converter. Converts based on the endianness of the current machine.
11 | ///
12 | internal sealed class ExifBitConverter : EndianBitConverter
13 | {
14 | ///
15 | /// The computer architecture info.
16 | ///
17 | private readonly IComputerArchitectureInfo computerArchitectureInfo;
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | ///
23 | /// The computer architecture info.
24 | ///
25 | public ExifBitConverter(IComputerArchitectureInfo computerArchitectureInfo) => this.computerArchitectureInfo = computerArchitectureInfo;
26 |
27 | ///
28 | public override Endianness Endianness => this.IsLittleEndian() ? Endianness.LittleEndian : Endianness.BigEndian;
29 |
30 | ///
31 | public override bool IsLittleEndian() => this.computerArchitectureInfo.IsLittleEndian();
32 |
33 | ///
34 | /// Converts the given ascii string to an array of bytes optionally adding a null terminator.
35 | ///
36 | /// The string to convert.
37 | /// Whether to add a null terminator to the end of the string.
38 | /// The .
39 | public byte[] GetBytes(string value, bool addTerminator)
40 | {
41 | if (addTerminator)
42 | {
43 | value += '\0';
44 | }
45 |
46 | byte[] bytes = Encoding.ASCII.GetBytes(value);
47 |
48 | if (!this.IsLittleEndian())
49 | {
50 | Array.Reverse(bytes);
51 | }
52 |
53 | return bytes;
54 | }
55 |
56 | ///
57 | /// Converts the given ascii string to an array of bytes without adding a null terminator.
58 | ///
59 | /// The string to convert.
60 | /// The .
61 | public byte[] GetBytes(string value) => this.GetBytes(value, false);
62 |
63 | ///
64 | /// Converts the given unsigned rational number to an array of bytes.
65 | ///
66 | ///
67 | /// The containing the numerator and denominator.
68 | ///
69 | /// The .
70 | public byte[] GetBytes(Rational value)
71 | {
72 | byte[] num = this.GetBytes(value.Numerator);
73 | byte[] den = this.GetBytes(value.Denominator);
74 | byte[] data = new byte[8];
75 | Array.Copy(num, 0, data, 0, 4);
76 | Array.Copy(den, 0, data, 4, 4);
77 | return data;
78 | }
79 |
80 | ///
81 | /// Converts the given signed rational number to an array of bytes.
82 | ///
83 | ///
84 | /// The containing the numerator and denominator.
85 | ///
86 | /// The .
87 | public byte[] GetBytes(Rational value)
88 | {
89 | byte[] num = this.GetBytes(value.Numerator);
90 | byte[] den = this.GetBytes(value.Denominator);
91 | byte[] data = new byte[8];
92 | Array.Copy(num, 0, data, 0, 4);
93 | Array.Copy(den, 0, data, 4, 4);
94 | return data;
95 | }
96 |
97 | ///
98 | protected internal override long FromBytes(byte[] value, int startIndex, int bytesToConvert)
99 | {
100 | if (this.IsLittleEndian())
101 | {
102 | return Little.FromBytes(value, startIndex, bytesToConvert);
103 | }
104 |
105 | return Big.FromBytes(value, startIndex, bytesToConvert);
106 | }
107 |
108 | ///
109 | protected internal override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
110 | {
111 | if (this.IsLittleEndian())
112 | {
113 | Little.CopyBytesImpl(value, bytes, buffer, index);
114 | }
115 | else
116 | {
117 | Big.CopyBytesImpl(value, bytes, buffer, index);
118 | }
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Metadata/ExifPropertyTagConstants.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Linq;
6 |
7 | namespace ImageProcessor.Metadata
8 | {
9 | ///
10 | /// Contains constants grouping together common property items.
11 | ///
12 | public static class ExifPropertyTagConstants
13 | {
14 | ///
15 | /// Gets all required property items. The Gif format specifically requires these properties.
16 | ///
17 | public static readonly ExifPropertyTag[] RequiredPropertyItems =
18 | {
19 | ExifPropertyTag.LoopCount, ExifPropertyTag.FrameDelay
20 | };
21 |
22 | ///
23 | /// Gets all required property items plus geolocation specific property items.
24 | ///
25 | public static readonly ExifPropertyTag[] GeolocationPropertyItems = RequiredPropertyItems.Union(
26 | new[]
27 | {
28 | ExifPropertyTag.GpsAltitude,
29 | ExifPropertyTag.GpsAltitudeRef,
30 | ExifPropertyTag.GpsDestBear,
31 | ExifPropertyTag.GpsDestBearRef,
32 | ExifPropertyTag.GpsDestDist,
33 | ExifPropertyTag.GpsDestDistRef,
34 | ExifPropertyTag.GpsDestLat,
35 | ExifPropertyTag.GpsDestLatRef,
36 | ExifPropertyTag.GpsDestLong,
37 | ExifPropertyTag.GpsDestLongRef,
38 | ExifPropertyTag.GpsGpsDop,
39 | ExifPropertyTag.GpsGpsMeasureMode,
40 | ExifPropertyTag.GpsGpsSatellites,
41 | ExifPropertyTag.GpsGpsStatus,
42 | ExifPropertyTag.GpsGpsTime,
43 | ExifPropertyTag.GpsIFD,
44 | ExifPropertyTag.GpsImgDir,
45 | ExifPropertyTag.GpsImgDirRef,
46 | ExifPropertyTag.GpsLatitude,
47 | ExifPropertyTag.GpsLatitudeRef,
48 | ExifPropertyTag.GpsLongitude,
49 | ExifPropertyTag.GpsLongitudeRef,
50 | ExifPropertyTag.GpsMapDatum,
51 | ExifPropertyTag.GpsSpeed,
52 | ExifPropertyTag.GpsSpeedRef,
53 | ExifPropertyTag.GpsTrack,
54 | ExifPropertyTag.GpsTrackRef,
55 | ExifPropertyTag.GpsVer
56 | }).ToArray();
57 |
58 | ///
59 | /// Gets all required property items plus copyright specific property items.
60 | ///
61 | public static readonly ExifPropertyTag[] CopyrightPropertyItems = RequiredPropertyItems.Union(
62 | new[]
63 | {
64 | ExifPropertyTag.Copyright,
65 | ExifPropertyTag.Artist,
66 | ExifPropertyTag.ImageTitle,
67 | ExifPropertyTag.ImageDescription,
68 | ExifPropertyTag.ExifUserComment,
69 | ExifPropertyTag.EquipMake,
70 | ExifPropertyTag.EquipModel,
71 | ExifPropertyTag.ThumbnailArtist,
72 | ExifPropertyTag.ThumbnailCopyRight,
73 | ExifPropertyTag.ThumbnailImageDescription,
74 | ExifPropertyTag.ThumbnailEquipMake,
75 | ExifPropertyTag.ThumbnailEquipModel,
76 | }).ToArray();
77 |
78 | ///
79 | /// Gets all required property items plus copyright and geolocation specific property items.
80 | ///
81 | public static readonly ExifPropertyTag[] CopyrightAndGeolocationPropertyItems =
82 | GeolocationPropertyItems.Union(CopyrightPropertyItems).ToArray();
83 |
84 | ///
85 | /// Gets all known property items.
86 | ///
87 | public static readonly ExifPropertyTag[] All = (ExifPropertyTag[])Enum.GetValues(typeof(ExifPropertyTag));
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Metadata/ExifPropertyTagType.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Metadata
5 | {
6 | ///
7 | /// Specifies the data type of the values stored in the value data member of that same PropertyItem object.
8 | /// .
9 | ///
10 | public enum ExifPropertyTagType : short
11 | {
12 | ///
13 | /// Specifies that the value data member is an array of bytes.
14 | ///
15 | Byte = 1,
16 |
17 | ///
18 | /// Specifies that the value data member is a null-terminated ASCII string. If you set the type data member of a
19 | /// PropertyItem object to ExifPropertyTagTypeASCII, you should set the length data member to the length of the string
20 | /// including the NULL terminator. For example, the string HELLO would have a length of 6.
21 | ///
22 | ASCII = 2,
23 |
24 | ///
25 | /// Specifies that the value data member is an array of unsigned short (16-bit) integers.
26 | ///
27 | UShort = 3,
28 |
29 | ///
30 | /// Specifies that the value data member is an array of unsigned long (32-bit) integers.
31 | ///
32 | ULong = 4,
33 |
34 | ///
35 | /// Specifies that the value data member is an array of pairs of unsigned long integers. Each pair represents a
36 | /// fraction; the first integer is the numerator and the second integer is the denominator.
37 | ///
38 | Rational = 5,
39 |
40 | ///
41 | /// Specifies that the value data member is an array of bytes that can hold values of any data type.
42 | ///
43 | Undefined = 6,
44 |
45 | ///
46 | /// Specifies that the value data member is an array of signed long (32-bit) integers.
47 | ///
48 | SLong = 7,
49 |
50 | ///
51 | /// Specifies that the value data member is an array of pairs of signed long integers. Each pair represents a
52 | /// fraction; the first integer is the numerator and the second integer is the denominator.
53 | ///
54 | SRational = 10
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Metadata/Int32Converter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Runtime.InteropServices;
5 |
6 | namespace ImageProcessor.Metadata
7 | {
8 | ///
9 | /// Provides a way to convert integers to an array of bytes without creating multiple
10 | /// short term arrays.
11 | ///
12 | [StructLayout(LayoutKind.Explicit)]
13 | internal readonly struct Int32Converter
14 | {
15 | ///
16 | /// The value of the byte array as an integer.
17 | ///
18 | [FieldOffset(0)]
19 | public readonly int Value;
20 |
21 | ///
22 | /// The first byte.
23 | ///
24 | [FieldOffset(0)]
25 | public readonly byte Byte1;
26 |
27 | ///
28 | /// The second byte.
29 | ///
30 | [FieldOffset(1)]
31 | public readonly byte Byte2;
32 |
33 | ///
34 | /// The third byte.
35 | ///
36 | [FieldOffset(2)]
37 | public readonly byte Byte3;
38 |
39 | ///
40 | /// The fourth byte.
41 | ///
42 | [FieldOffset(3)]
43 | public readonly byte Byte4;
44 |
45 | ///
46 | /// Initializes a new instance of the struct.
47 | ///
48 | ///
49 | /// The value to convert from.
50 | ///
51 | public Int32Converter(int value)
52 | : this() => this.Value = value;
53 |
54 | ///
55 | /// Allows the implicit conversion of an instance of to a .
56 | ///
57 | ///
58 | /// The instance of to convert.
59 | ///
60 | /// An instance of .
61 | public static implicit operator int(Int32Converter value) => value.Value;
62 |
63 | ///
64 | /// Allows the implicit conversion of an instance of to a .
65 | ///
66 | /// The instance of to convert.
67 | /// An instance of .
68 | public static implicit operator Int32Converter(int value) => new Int32Converter(value);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Metadata/PropertyTagResolutionUnit.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Metadata
5 | {
6 | ///
7 | /// The following enum gives the unit of measure for the horizontal resolution and the vertical resolution
8 | /// supported by Windows GDI+.
9 | /// .
10 | ///
11 | public enum PropertyTagResolutionUnit : ushort
12 | {
13 | ///
14 | /// The resolution is measured in pixels per inch.
15 | ///
16 | Inch = 2,
17 |
18 | ///
19 | /// The resolution is measured in pixels per centimeter.
20 | ///
21 | Cm = 3
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/ImageProcessor/MetadataMode.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor
5 | {
6 | ///
7 | /// Enumerates the various metadata modes that control how much metadata information is stored on processing.
8 | ///
9 | public enum MetadataMode
10 | {
11 | ///
12 | /// Store no metadata on processing
13 | ///
14 | All,
15 |
16 | ///
17 | /// Store copyright specific metadata on processing
18 | ///
19 | Copyright,
20 |
21 | ///
22 | /// Store geolocation specific metadata on processing
23 | ///
24 | Geolocation,
25 |
26 | ///
27 | /// Store copyright and geolocation specific metadata on processing
28 | ///
29 | CopyrightAndGeolocation,
30 |
31 | ///
32 | /// Store all metadata on processing
33 | ///
34 | None
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Adjustments.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Drawing;
6 | using System.Threading.Tasks;
7 |
8 | namespace ImageProcessor.Processing
9 | {
10 | ///
11 | /// Provides reusable adjustment methods to apply to images.
12 | ///
13 | public static class Adjustments
14 | {
15 | ///
16 | /// Adjust the gamma (intensity of the light) component of the given image.
17 | ///
18 | /// The source to adjust.
19 | /// The value to adjust the gamma by (typically between .2 and 5).
20 | ///
21 | /// The with the gamma adjusted.
22 | ///
23 | ///
24 | /// Thrown if the value falls outside the acceptable range.
25 | ///
26 | public static Bitmap Gamma(Image source, float value)
27 | {
28 | if (value > 5 || value < .1)
29 | {
30 | throw new ArgumentOutOfRangeException(nameof(value), "Value should be between .1 and 5.");
31 | }
32 |
33 | byte[] ramp = new byte[256];
34 | for (int x = 0; x < 256; ++x)
35 | {
36 | ramp[x] = ((255 * Math.Pow(x / 255D, value)) + 0.5).ToByte();
37 | }
38 |
39 | int width = source.Width;
40 | int height = source.Height;
41 |
42 | using (var bitmap = new FastBitmap(source))
43 | {
44 | Parallel.For(
45 | 0,
46 | height,
47 | y =>
48 | {
49 | for (int x = 0; x < width; x++)
50 | {
51 | Color composite = bitmap.GetPixel(x, y);
52 | var linear = Color.FromArgb(composite.A, ramp[composite.R], ramp[composite.G], ramp[composite.B]);
53 | bitmap.SetPixel(x, y, linear);
54 | }
55 | });
56 | }
57 |
58 | return (Bitmap)source;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Alpha.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 |
7 | namespace ImageProcessor.Processing
8 | {
9 | ///
10 | /// Changes the alpha component of the image.
11 | ///
12 | public class Alpha : ColorMatrixRangedProcessor
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | ///
18 | /// The percentage by which to alter the images opacity. Range 0..100.
19 | ///
20 | public Alpha(float percentage)
21 | : base(percentage)
22 | {
23 | }
24 |
25 | ///
26 | public override Image ProcessImageFrame(ImageFactory factory, Image frame)
27 | {
28 | float amount = this.Options / 100;
29 | ColorMatrix colorMatrix = KnownColorMatrices.CreateOpacityFilter(amount);
30 | ApplyMatrix(frame, colorMatrix);
31 |
32 | return frame;
33 | }
34 |
35 | ///
36 | protected override void GuardRange(float amount)
37 | {
38 | if (amount < 0 || amount > 100)
39 | {
40 | throw new ImageProcessingException($"{nameof(amount)} must be in range 0..100");
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/AutoRotate.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 | using ImageProcessor.Metadata;
7 |
8 | namespace ImageProcessor.Processing
9 | {
10 | ///
11 | /// Performs auto-rotation to ensure that EXIF defined rotation is reflected in
12 | /// the final image. .
13 | ///
14 | public class AutoRotate : IGraphicsProcessor
15 | {
16 | ///
17 | public Image ProcessImageFrame(ImageFactory factory, Image frame)
18 | {
19 | const int Orientation = (int)ExifPropertyTag.Orientation;
20 |
21 | // Images are always rotated before and after processing if there is an
22 | // orientation key present. By removing the property item we prevent the reverse
23 | // rotation.
24 | if (factory.MetadataMode != MetadataMode.All
25 | && factory.PropertyItems.ContainsKey(Orientation))
26 | {
27 | factory.PropertyItems.TryRemove(Orientation, out PropertyItem _);
28 | }
29 |
30 | return frame;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/BackgroundColor.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 |
6 | namespace ImageProcessor.Processing
7 | {
8 | ///
9 | /// Changes the background color of an image.
10 | ///
11 | public class BackgroundColor : IGraphicsProcessor
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The color to set.
17 | public BackgroundColor(Color color) => this.Options = color;
18 |
19 | ///
20 | public Color Options { get; }
21 |
22 | ///
23 | public Image ProcessImageFrame(ImageFactory factory, Image frame)
24 | {
25 | Bitmap result = FormatUtilities.CreateEmptyFrameFrom(frame);
26 |
27 | using (var graphics = Graphics.FromImage(result))
28 | {
29 | graphics.PageUnit = GraphicsUnit.Pixel;
30 | graphics.Clear(this.Options);
31 |
32 | graphics.DrawImageUnscaled(frame, 0, 0);
33 | }
34 |
35 | frame.Dispose();
36 | return result;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Brightness.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 |
7 | namespace ImageProcessor.Processing
8 | {
9 | ///
10 | /// Changes the brightness component of the image.
11 | ///
12 | public class Brightness : ColorMatrixRangedProcessor
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | ///
18 | /// The percentage by which to alter the images brightness. Range -100..100.
19 | ///
20 | public Brightness(float amount)
21 | : base(amount)
22 | {
23 | }
24 |
25 | ///
26 | public override Image ProcessImageFrame(ImageFactory factory, Image frame)
27 | {
28 | float amount = (this.Options + 100) / 100;
29 | ColorMatrix colorMatrix = KnownColorMatrices.CreateBrightnessFilter(amount);
30 | ApplyMatrix(frame, colorMatrix);
31 |
32 | return frame;
33 | }
34 |
35 | ///
36 | protected override void GuardRange(float amount)
37 | {
38 | if (amount < -100 || amount > 100)
39 | {
40 | throw new ImageProcessingException($"{nameof(amount)} must be in Range -100..100");
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/ColorMatrixProcessor.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Drawing2D;
6 | using System.Drawing.Imaging;
7 |
8 | namespace ImageProcessor.Processing
9 | {
10 | ///
11 | /// A base class for processing images via color matrices.
12 | ///
13 | public abstract class ColorMatrixProcessor : IGraphicsProcessor
14 | {
15 | ///
16 | public abstract Image ProcessImageFrame(ImageFactory factory, Image frame);
17 |
18 | ///
19 | /// Performs the application of the color matrix upon the image.
20 | ///
21 | /// The image frame.
22 | /// The color matrix.
23 | protected static void ApplyMatrix(Image frame, ColorMatrix colorMatrix)
24 | {
25 | using (var graphics = Graphics.FromImage(frame))
26 | {
27 | using (var imageAttributes = new ImageAttributes())
28 | {
29 | imageAttributes.SetColorMatrix(
30 | colorMatrix,
31 | ColorMatrixFlag.Default,
32 | ColorAdjustType.Bitmap);
33 |
34 | graphics.CompositingMode = CompositingMode.SourceCopy;
35 | graphics.DrawImage(
36 | frame,
37 | new Rectangle(0, 0, frame.Width, frame.Height),
38 | 0,
39 | 0,
40 | frame.Width,
41 | frame.Height,
42 | GraphicsUnit.Pixel,
43 | imageAttributes);
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/ColorMatrixRangedProcessor.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// A base class for processing images via color matrices.
8 | ///
9 | public abstract class ColorMatrixRangedProcessor : ColorMatrixProcessor, IGraphicsProcessor
10 | {
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | /// The amount by which to adjust the matrix.
15 | protected ColorMatrixRangedProcessor(float amount)
16 | {
17 | this.GuardRange(amount);
18 | this.Options = amount;
19 | }
20 |
21 | ///
22 | public float Options { get; }
23 |
24 | ///
25 | /// A method for protecting input thresholds.
26 | ///
27 | /// The amount to check.
28 | ///
29 | /// Thrown if the range is outith the acceptable threshold.
30 | ///
31 | protected virtual void GuardRange(float amount)
32 | {
33 | // Default to no-op.
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Contrast.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 |
7 | namespace ImageProcessor.Processing
8 | {
9 | ///
10 | /// Changes the contrast component of the image.
11 | ///
12 | public class Contrast : ColorMatrixRangedProcessor
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | ///
18 | /// The percentage by which to alter the images contrast. Range -100..100.
19 | ///
20 | public Contrast(float amount)
21 | : base(amount)
22 | {
23 | }
24 |
25 | ///
26 | public override Image ProcessImageFrame(ImageFactory factory, Image frame)
27 | {
28 | float amount = (this.Options + 100) / 100;
29 | ColorMatrix colorMatrix = KnownColorMatrices.CreateContrastFilter(amount);
30 | ApplyMatrix(frame, colorMatrix);
31 |
32 | return frame;
33 | }
34 |
35 | ///
36 | protected override void GuardRange(float amount)
37 | {
38 | if (amount < -100 || amount > 100)
39 | {
40 | throw new ImageProcessingException($"{nameof(amount)} must be in Range -100..100");
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/EdgeDetection2DProcessor.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 |
6 | namespace ImageProcessor.Processing
7 | {
8 | ///
9 | /// A base class for processing images using edge detection.
10 | ///
11 | public abstract class EdgeDetection2DProcessor : IGraphicsProcessor, IGraphicsProcessor
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The horizontal and vertical kernel operators.
17 | /// Whether to convert the image to grascale before processing.
18 | protected EdgeDetection2DProcessor(KernelPair kernels, bool grayscale)
19 | {
20 | this.Kernels = kernels;
21 | this.Grayscale = grayscale;
22 | }
23 |
24 | ///
25 | /// Gets the kernel operator pair.
26 | ///
27 | public KernelPair Kernels { get; }
28 |
29 | ///
30 | /// Gets a value indicating whether to convert the image to grascale before processing.
31 | ///
32 | public bool Grayscale { get; }
33 |
34 | ///
35 | KernelPair IGraphicsProcessor.Options
36 | {
37 | get { return this.Kernels; }
38 | }
39 |
40 | ///
41 | bool IGraphicsProcessor.Options
42 | {
43 | get { return this.Grayscale; }
44 | }
45 |
46 | ///
47 | public Image ProcessImageFrame(ImageFactory factory, Image frame)
48 | {
49 | if (this.Grayscale)
50 | {
51 | // Grayscale is not destructive and will return the same image.
52 | frame = new Grayscale(100F).ProcessImageFrame(factory, frame);
53 | }
54 |
55 | // Convolution is destructive and will create a new image.
56 | Image result = new Convolution2DProcessor(this.Kernels).ProcessImageFrame(factory, frame);
57 |
58 | frame.Dispose();
59 | return result;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/EdgeDetectionOperators.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Enumerates the various types of defined edge detection filters.
8 | ///
9 | public enum EdgeDetectionOperators
10 | {
11 | ///
12 | /// The Kayyali operator filter.
13 | ///
14 | Kayyali,
15 |
16 | ///
17 | /// The Laplacian3X3 operator filter.
18 | ///
19 | Laplacian3x3,
20 |
21 | ///
22 | /// The Laplacian5X5 operator filter.
23 | ///
24 | Laplacian5x5,
25 |
26 | ///
27 | /// The LaplacianOfGaussian operator filter.
28 | ///
29 | LaplacianOfGaussian,
30 |
31 | ///
32 | /// The Prewitt operator filter.
33 | ///
34 | Prewitt,
35 |
36 | ///
37 | /// The RobertsCross operator filter.
38 | ///
39 | RobertsCross,
40 |
41 | ///
42 | /// The Scharr operator filter.
43 | ///
44 | Scharr,
45 |
46 | ///
47 | /// The Sobel operator filter.
48 | ///
49 | Sobel
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/EdgeDetectionProcessor.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 |
6 | namespace ImageProcessor.Processing
7 | {
8 | ///
9 | /// A base class for processing images using edge detection.
10 | ///
11 | public abstract class EdgeDetectionProcessor : IGraphicsProcessor, IGraphicsProcessor
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The kernel operator.
17 | /// Whether to convert the image to grascale before processing.
18 | protected EdgeDetectionProcessor(double[,] kernel, bool grayscale)
19 | {
20 | this.Kernel = kernel;
21 | this.Grayscale = grayscale;
22 | }
23 |
24 | ///
25 | /// Gets the kernel operator.
26 | ///
27 | public double[,] Kernel { get; }
28 |
29 | ///
30 | /// Gets a value indicating whether to convert the image to grascale before processing.
31 | ///
32 | public bool Grayscale { get; }
33 |
34 | ///
35 | double[,] IGraphicsProcessor.Options
36 | {
37 | get { return this.Kernel; }
38 | }
39 |
40 | ///
41 | bool IGraphicsProcessor.Options
42 | {
43 | get { return this.Grayscale; }
44 | }
45 |
46 | ///
47 | public Image ProcessImageFrame(ImageFactory factory, Image frame)
48 | {
49 | if (this.Grayscale)
50 | {
51 | // Grayscale is not destructive and will return the same image.
52 | frame = new Grayscale(100F).ProcessImageFrame(factory, frame);
53 | }
54 |
55 | // Convolution is destructive and will create a new image.
56 | Image result = new ConvolutionProcessor(this.Kernel).ProcessImageFrame(factory, frame);
57 |
58 | frame.Dispose();
59 | return result;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/Kayyali.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using Kayyali operators.
8 | /// .
9 | ///
10 | public class Kayyali : EdgeDetection2DProcessor
11 | {
12 | private static readonly double[,] KernelX = new double[,]
13 | {
14 | { 6, 0, -6 },
15 | { 0, 0, 0 },
16 | { -6, 0, 6 }
17 | };
18 |
19 | private static readonly double[,] KernelY = new double[,]
20 | {
21 | { -6, 0, 6 },
22 | { 0, 0, 0 },
23 | { 6, 0, -6 }
24 | };
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// Whether to convert the image to grascale before processing.
30 | public Kayyali(bool grayscale)
31 | : base(new KernelPair(KernelX, KernelY), grayscale)
32 | {
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/Laplacian3x3.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using Laplacian 3x3 operators.
8 | /// .
9 | ///
10 | public class Laplacian3x3 : EdgeDetectionProcessor
11 | {
12 | private static readonly double[,] KernelXY = new double[,]
13 | {
14 | { -1, -1, -1 },
15 | { -1, 8, -1 },
16 | { -1, -1, -1 }
17 | };
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | /// Whether to convert the image to grascale before processing.
23 | public Laplacian3x3(bool grayscale)
24 | : base(KernelXY, grayscale)
25 | {
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/Laplacian5x5.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using Laplacian 5x5 operators.
8 | /// .
9 | ///
10 | public class Laplacian5x5 : EdgeDetectionProcessor
11 | {
12 | private static readonly double[,] KernelXY = new double[,]
13 | {
14 | { -1, -1, -1, -1, -1 },
15 | { -1, -1, -1, -1, -1 },
16 | { -1, -1, 24, -1, -1 },
17 | { -1, -1, -1, -1, -1 },
18 | { -1, -1, -1, -1, -1 }
19 | };
20 |
21 | ///
22 | /// Initializes a new instance of the class.
23 | ///
24 | /// Whether to convert the image to grascale before processing.
25 | public Laplacian5x5(bool grayscale)
26 | : base(KernelXY, grayscale)
27 | {
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/LaplacianOfGaussian.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using Laplacian of Gaussian operators.
8 | /// .
9 | ///
10 | public class LaplacianOfGaussian : EdgeDetectionProcessor
11 | {
12 | private static readonly double[,] KernelXY = new double[,]
13 | {
14 | { 0, 0, -1, 0, 0 },
15 | { 0, -1, -2, -1, 0 },
16 | { -1, -2, 16, -2, -1 },
17 | { 0, -1, -2, -1, 0 },
18 | { 0, 0, -1, 0, 0 }
19 | };
20 |
21 | ///
22 | /// Initializes a new instance of the class.
23 | ///
24 | /// Whether to convert the image to grascale before processing.
25 | public LaplacianOfGaussian(bool grayscale)
26 | : base(KernelXY, grayscale)
27 | {
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/Prewitt.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using Prewitt operators.
8 | /// .
9 | ///
10 | public class Prewitt : EdgeDetection2DProcessor
11 | {
12 | private static readonly double[,] KernelX = new double[,]
13 | {
14 | { -1, 0, 1 },
15 | { -1, 0, 1 },
16 | { -1, 0, 1 }
17 | };
18 |
19 | private static readonly double[,] KernelY = new double[,]
20 | {
21 | { 1, 1, 1 },
22 | { 0, 0, 0 },
23 | { -1, -1, -1 }
24 | };
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// Whether to convert the image to grascale before processing.
30 | public Prewitt(bool grayscale)
31 | : base(new KernelPair(KernelX, KernelY), grayscale)
32 | {
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/RobertsCross.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using RobertsCross operators.
8 | /// .
9 | ///
10 | public class RobertsCross : EdgeDetection2DProcessor
11 | {
12 | private static readonly double[,] KernelX = new double[,]
13 | {
14 | { 1, 0 },
15 | { 0, -1 }
16 | };
17 |
18 | private static readonly double[,] KernelY = new double[,]
19 | {
20 | { 0, 1 },
21 | { -1, 0 }
22 | };
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// Whether to convert the image to grascale before processing.
28 | public RobertsCross(bool grayscale)
29 | : base(new KernelPair(KernelX, KernelY), grayscale)
30 | {
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/Scharr.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using Scharr operators.
8 | /// .
9 | ///
10 | public class Scharr : EdgeDetection2DProcessor
11 | {
12 | private static readonly double[,] KernelX = new double[,]
13 | {
14 | { -3, 0, 3 },
15 | { -10, 0, 10 },
16 | { -3, 0, 3 }
17 | };
18 |
19 | private static readonly double[,] KernelY = new double[,]
20 | {
21 | { 3, 10, 3 },
22 | { 0, 0, 0 },
23 | { -3, -10, -3 }
24 | };
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// Whether to convert the image to grascale before processing.
30 | public Scharr(bool grayscale)
31 | : base(new KernelPair(KernelX, KernelY), grayscale)
32 | {
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Convolution/Sobel.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Processing
5 | {
6 | ///
7 | /// Detects edges within an image using Sobel operators.
8 | /// .
9 | ///
10 | public class Sobel : EdgeDetection2DProcessor
11 | {
12 | private static readonly double[,] KernelX = new double[,]
13 | {
14 | { -1, 0, 1 },
15 | { -2, 0, 2 },
16 | { -1, 0, 1 }
17 | };
18 |
19 | private static readonly double[,] KernelY = new double[,]
20 | {
21 | { 1, 2, 1 },
22 | { 0, 0, 0 },
23 | { -1, -2, -1 }
24 | };
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// Whether to convert the image to grascale before processing.
30 | public Sobel(bool grayscale)
31 | : base(new KernelPair(KernelX, KernelY), grayscale)
32 | {
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Grayscale.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 |
7 | namespace ImageProcessor.Processing
8 | {
9 | ///
10 | /// Changes the grayscale component of the image using the formula as specified by ITU-R Recommendation BT.601.
11 | /// .
12 | ///
13 | public class Grayscale : ColorMatrixRangedProcessor
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | ///
19 | /// The percentage by which to alter the images opacity. Range 0..100.
20 | ///
21 | public Grayscale(float percentage)
22 | : base(percentage)
23 | {
24 | }
25 |
26 | ///
27 | public override Image ProcessImageFrame(ImageFactory factory, Image frame)
28 | {
29 | float amount = this.Options / 100;
30 | ColorMatrix colorMatrix = KnownColorMatrices.CreateGrayscaleFilter(amount);
31 | ApplyMatrix(frame, colorMatrix);
32 |
33 | return frame;
34 | }
35 |
36 | ///
37 | protected override void GuardRange(float amount)
38 | {
39 | if (amount < 0 || amount > 100)
40 | {
41 | throw new ImageProcessingException($"{nameof(amount)} must be in range 0..100");
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Hue.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 |
7 | namespace ImageProcessor.Processing
8 | {
9 | ///
10 | /// Changes the hue component of the image.
11 | ///
12 | public class Hue : ColorMatrixRangedProcessor
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// The rotation angle in degrees to adjust the hue.
18 | public Hue(float degrees)
19 | : base(degrees)
20 | {
21 | }
22 |
23 | ///
24 | public override Image ProcessImageFrame(ImageFactory factory, Image frame)
25 | {
26 | ColorMatrix colorMatrix = KnownColorMatrices.CreateHueFilter(this.Options);
27 | ApplyMatrix(frame, colorMatrix);
28 |
29 | return frame;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/IGraphicsProcessor.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 |
6 | namespace ImageProcessor.Processing
7 | {
8 | ///
9 | /// Defines the contract for graphics processors.
10 | ///
11 | public interface IGraphicsProcessor
12 | {
13 | ///
14 | /// Returns a new image frame from the source with the process applied.
15 | ///
16 | /// The class.
17 | /// The source image frame.
18 | /// The .
19 | Image ProcessImageFrame(ImageFactory factory, Image frame);
20 | }
21 |
22 | ///
23 | /// Defines the contract for graphics processors with options.
24 | ///
25 | /// The type of options.
26 | public interface IGraphicsProcessor : IGraphicsProcessor
27 | {
28 | ///
29 | /// Gets the options.
30 | ///
31 | T Options { get; }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Pixelate.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Drawing;
7 | using System.Threading.Tasks;
8 |
9 | namespace ImageProcessor.Processing
10 | {
11 | ///
12 | /// Pixelates an image.
13 | ///
14 | public class Pixelate : IGraphicsProcessor
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The pixelate options.
20 | public Pixelate(PixelateOptions options) => this.Options = options;
21 |
22 | ///
23 | public PixelateOptions Options { get; }
24 |
25 | ///
26 | public Image ProcessImageFrame(ImageFactory factory, Image frame)
27 | {
28 | int size = this.Options.Size;
29 | var rectangle = Rectangle.Intersect(this.Options.Rectangle, new Rectangle(Point.Empty, frame.Size));
30 | int startX = rectangle.X;
31 | int startY = rectangle.Y;
32 | int offset = size / 2;
33 | int maxX = rectangle.Right;
34 | int maxY = rectangle.Bottom;
35 |
36 | // Align start/end positions.
37 | int minX = Math.Max(0, startX);
38 | int minY = Math.Max(0, startY);
39 |
40 | // Reset offset if necessary.
41 | if (minX > 0)
42 | {
43 | startX = 0;
44 | }
45 |
46 | if (minY > 0)
47 | {
48 | startY = 0;
49 | }
50 |
51 | using (var fastBitmap = new FastBitmap(frame))
52 | {
53 | // Get the range on the y-plane to choose from.
54 | IEnumerable range = EnumerableUtilities.SteppedRange(minY, maxY, size);
55 |
56 | Parallel.ForEach(
57 | range,
58 | y =>
59 | {
60 | int offsetY = y - startY;
61 | int offsetPy = offset;
62 |
63 | // Make sure that the offset is within the boundary of the image.
64 | while (offsetY + offsetPy >= maxY)
65 | {
66 | offsetPy--;
67 | }
68 |
69 | for (int x = minX; x < maxX; x += size)
70 | {
71 | int offsetX = x - startX;
72 | int offsetPx = offset;
73 |
74 | while (x + offsetPx >= maxX)
75 | {
76 | offsetPx--;
77 | }
78 |
79 | // Get the pixel color in the centre of the soon to be pixelated area.
80 | Color pixel = fastBitmap.GetPixel(offsetX + offsetPx, offsetY + offsetPy);
81 |
82 | // For each pixel in the pixelate size, set it to the centre color.
83 | for (int l = offsetY; l < offsetY + size && l < maxY; l++)
84 | {
85 | for (int k = offsetX; k < offsetX + size && k < maxX; k++)
86 | {
87 | fastBitmap.SetPixel(k, l, pixel);
88 | }
89 | }
90 | }
91 | });
92 | }
93 |
94 | return frame;
95 | }
96 | }
97 |
98 | ///
99 | /// The pixelate options for pixelating images.
100 | ///
101 | public class PixelateOptions
102 | {
103 | ///
104 | /// Initializes a new instance of the class.
105 | ///
106 | /// The pixel size.
107 | /// The bounds within which to pixelate.
108 | public PixelateOptions(int size, Rectangle rectangle)
109 | {
110 | if (size < 1)
111 | {
112 | throw new ImageProcessingException($"{nameof(size)} must be >= 1.");
113 | }
114 |
115 | if (rectangle == default)
116 | {
117 | throw new ImageProcessingException($"{nameof(rectangle)} must have value");
118 | }
119 |
120 | this.Size = size;
121 | this.Rectangle = rectangle;
122 | }
123 |
124 | ///
125 | /// Gets the size of the pixels.
126 | ///
127 | public int Size { get; }
128 |
129 | ///
130 | /// Gets the rectangle bounds within which to pixelate.
131 | ///
132 | public Rectangle Rectangle { get; }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Processing/Saturation.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 |
7 | namespace ImageProcessor.Processing
8 | {
9 | ///
10 | /// Changes the saturation component of the image.
11 | ///
12 | public class Saturation : ColorMatrixRangedProcessor
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | ///
18 | /// The percentage by which to alter the images saturation. Range -100..100.
19 | ///
20 | public Saturation(float amount)
21 | : base(amount)
22 | {
23 | }
24 |
25 | ///
26 | public override Image ProcessImageFrame(ImageFactory factory, Image frame)
27 | {
28 | float amount = (this.Options + 100) / 100;
29 | ColorMatrix colorMatrix = KnownColorMatrices.CreateSaturationFilter(amount);
30 | ApplyMatrix(frame, colorMatrix);
31 |
32 | return frame;
33 | }
34 |
35 | ///
36 | protected override void GuardRange(float amount)
37 | {
38 | if (amount < -100 || amount > 100)
39 | {
40 | throw new ImageProcessingException($"{nameof(amount)} {amount} must be in Range -100..100");
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Quantizers/IQuantizer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 |
6 | namespace ImageProcessor.Quantizers
7 | {
8 | ///
9 | /// Defines the contract for allowing quantization of images.
10 | ///
11 | public interface IQuantizer
12 | {
13 | ///
14 | /// Quantize an image and returns the resulting output bitmap.
15 | /// TODO: This should copy metadata.
16 | ///
17 | /// The image to quantize.
18 | /// .
19 | Bitmap Quantize(Image source);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Quantizers/WuQuantizer/Box.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Quantizers
5 | {
6 | ///
7 | /// The box for storing color attributes.
8 | /// Adapted from .
9 | ///
10 | public struct Box
11 | {
12 | ///
13 | /// The alpha maximum.
14 | ///
15 | public byte AlphaMaximum;
16 |
17 | ///
18 | /// The alpha minimum.
19 | ///
20 | public byte AlphaMinimum;
21 |
22 | ///
23 | /// The blue maximum.
24 | ///
25 | public byte BlueMaximum;
26 |
27 | ///
28 | /// The blue minimum.
29 | ///
30 | public byte BlueMinimum;
31 |
32 | ///
33 | /// The green maximum.
34 | ///
35 | public byte GreenMaximum;
36 |
37 | ///
38 | /// The green minimum.
39 | ///
40 | public byte GreenMinimum;
41 |
42 | ///
43 | /// The red maximum.
44 | ///
45 | public byte RedMaximum;
46 |
47 | ///
48 | /// The red minimum.
49 | ///
50 | public byte RedMinimum;
51 |
52 | ///
53 | /// The size.
54 | ///
55 | public int Size;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Quantizers/WuQuantizer/CubeCut.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace ImageProcessor.Quantizers
5 | {
6 | ///
7 | /// Represents a cube cut.
8 | /// Adapted from .
9 | ///
10 | internal readonly struct CubeCut
11 | {
12 | ///
13 | /// The position.
14 | ///
15 | public readonly byte? Position;
16 |
17 | ///
18 | /// The value.
19 | ///
20 | public readonly float Value;
21 |
22 | ///
23 | /// Initializes a new instance of the struct.
24 | ///
25 | /// The cut point.
26 | /// The result.
27 | public CubeCut(byte? cutPoint, float result)
28 | {
29 | this.Position = cutPoint;
30 | this.Value = result;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Quantizers/WuQuantizer/Histogram.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 |
6 | namespace ImageProcessor.Quantizers
7 | {
8 | ///
9 | /// The histogram representing the distribution of color data.
10 | /// Adapted from .
11 | ///
12 | internal class Histogram
13 | {
14 | ///
15 | /// The side size.
16 | ///
17 | private const int SideSize = 33;
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | public Histogram()
23 | {
24 | // 47,436,840 bytes
25 | this.Moments = new ColorMoment[SideSize, SideSize, SideSize, SideSize];
26 | }
27 |
28 | ///
29 | /// Gets the collection of moments.
30 | ///
31 | public ColorMoment[,,,] Moments { get; }
32 |
33 | ///
34 | /// Clears the histogram.
35 | ///
36 | internal void Clear() => Array.Clear(this.Moments, 0, SideSize * SideSize * SideSize * SideSize);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Quantizers/WuQuantizer/IWuQuantizer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 |
6 | namespace ImageProcessor.Quantizers
7 | {
8 | ///
9 | /// Encapsulates methods to calculate the color palette of an image using
10 | /// a Wu color quantizer .
11 | /// Adapted from .
12 | ///
13 | public interface IWuQuantizer : IQuantizer
14 | {
15 | ///
16 | /// Quantizes the given image.
17 | ///
18 | /// The 32 bit per pixel .
19 | ///
20 | /// The alpha threshold. All colors with an alpha value less than this will be
21 | /// considered fully transparent.
22 | ///
23 | ///
24 | /// The alpha fader. Alpha values will be normalized to the nearest multiple of this value.
25 | ///
26 | ///
27 | /// The quantized .
28 | ///
29 | Bitmap Quantize(Image image, int alphaThreshold, int alphaFader);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Quantizers/WuQuantizer/ImageBuffer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Drawing;
7 | using System.Drawing.Imaging;
8 | using System.Runtime.InteropServices;
9 |
10 | namespace ImageProcessor.Quantizers
11 | {
12 | ///
13 | /// The image buffer for storing and manipulating pixel information.
14 | /// Adapted from .
15 | ///
16 | internal class ImageBuffer
17 | {
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | /// The image to store.
22 | public ImageBuffer(Bitmap image) => this.Image = image;
23 |
24 | ///
25 | /// Gets the image.
26 | ///
27 | public Bitmap Image { get; }
28 |
29 | ///
30 | /// Gets the enumerable pixel array representing each row of pixels.
31 | ///
32 | ///
33 | /// Thrown if the given image is not a 32 bit per pixel image.
34 | ///
35 | public IEnumerable PixelLines
36 | {
37 | get
38 | {
39 | int width = this.Image.Width;
40 | int height = this.Image.Height;
41 | var pixels = new Bgra32[width];
42 |
43 | using (var bitmap = new FastBitmap(this.Image))
44 | {
45 | for (int y = 0; y < height; y++)
46 | {
47 | for (int x = 0; x < width; x++)
48 | {
49 | Color color = bitmap.GetPixel(x, y);
50 | pixels[x] = new Bgra32(color.A, color.R, color.G, color.B);
51 | }
52 |
53 | yield return pixels;
54 | }
55 | }
56 | }
57 | }
58 |
59 | ///
60 | /// Updates the pixel indexes.
61 | ///
62 | ///
63 | /// The enumerable byte array representing each row of pixels.
64 | ///
65 | public void UpdatePixelIndexes(IEnumerable lineIndexes)
66 | {
67 | int width = this.Image.Width;
68 | int height = this.Image.Height;
69 | int rowIndex = 0;
70 |
71 | BitmapData data = this.Image.LockBits(Rectangle.FromLTRB(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
72 | try
73 | {
74 | IntPtr pixelBase = data.Scan0;
75 | int scanWidth = data.Stride;
76 | foreach (byte[] scanLine in lineIndexes)
77 | {
78 | Marshal.Copy(scanLine, 0, IntPtr.Add(pixelBase, scanWidth * rowIndex), width);
79 |
80 | if (++rowIndex >= height)
81 | {
82 | break;
83 | }
84 | }
85 | }
86 | finally
87 | {
88 | this.Image.UnlockBits(data);
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/ImageProcessor/Quantizers/WuQuantizer/PaletteColorHistory.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) James Jackson-South and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Drawing;
5 |
6 | namespace ImageProcessor.Quantizers
7 | {
8 | ///
9 | /// The palette color history containing the sum of all pixel data.
10 | /// Adapted from .
11 | ///
12 | internal struct PaletteColorHistory
13 | {
14 | ///
15 | /// The alpha component.
16 | ///
17 | public ulong Alpha;
18 |
19 | ///
20 | /// The red component.
21 | ///
22 | public ulong Red;
23 |
24 | ///
25 | /// The green component.
26 | ///
27 | public ulong Green;
28 |
29 | ///
30 | /// The blue component.
31 | ///
32 | public ulong Blue;
33 |
34 | ///
35 | /// The sum of the color components.
36 | ///
37 | public ulong Sum;
38 |
39 | ///
40 | /// Normalizes the color.
41 | ///
42 | ///
43 | /// The normalized .
44 | ///
45 | public Color ToNormalizedColor() => (this.Sum != 0) ? Color.FromArgb((int)(this.Alpha /= this.Sum), (int)(this.Red /= this.Sum), (int)(this.Green /= this.Sum), (int)(this.Blue /= this.Sum)) : Color.Empty;
46 |
47 | ///
48 | /// Adds a pixel to the color history.
49 | ///
50 | ///
51 | /// The pixel to add.
52 | ///
53 | public void AddPixel(Bgra32 pixel)
54 | {
55 | this.Alpha += pixel.A;
56 | this.Red += pixel.R;
57 | this.Green += pixel.G;
58 | this.Blue += pixel.B;
59 | this.Sum++;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
3 | "settings": {
4 | "orderingRules": {
5 | "usingDirectivesPlacement": "outsideNamespace",
6 | "elementOrder": [
7 | "kind"
8 | ]
9 | },
10 | "documentationRules": {
11 | "xmlHeader": false,
12 | "documentInternalElements": false,
13 | "copyrightText": "Copyright (c) James Jackson-South and contributors.\nLicensed under the Apache License, Version 2.0."
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tests/ImageProcessor.Tests/FastBitmapTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Drawing.Imaging;
4 | using Xunit;
5 |
6 | namespace ImageProcessor.Tests
7 | {
8 | public class FastBitmapTests
9 | {
10 | [Theory]
11 | [InlineData(PixelFormat.Format1bppIndexed)]
12 | [InlineData(PixelFormat.Format4bppIndexed)]
13 | [InlineData(PixelFormat.Format8bppIndexed)]
14 | public void FastBitmapConstructorChecksInput(PixelFormat format)
15 | {
16 | using (var image = new Bitmap(1, 1, format))
17 | {
18 | Assert.Throws(() =>
19 | {
20 | using (var fast = new FastBitmap(image))
21 | {
22 | }
23 | });
24 | }
25 | }
26 |
27 | [Theory]
28 | [InlineData(PixelFormat.Format16bppRgb565)]
29 | [InlineData(PixelFormat.Format24bppRgb)]
30 | [InlineData(PixelFormat.Format32bppRgb)]
31 | [InlineData(PixelFormat.Format32bppArgb)]
32 | [InlineData(PixelFormat.Format32bppPArgb)]
33 | [InlineData(PixelFormat.Format48bppRgb)]
34 | public void FastBitmapCanManipulatePixels(PixelFormat format)
35 | {
36 | using (var image = new Bitmap(5, 5, format))
37 | {
38 | var expected = Color.FromArgb(16, 32, 64, 128);
39 | using (var fast = new FastBitmap(image))
40 | {
41 | for (int y = 0; y < fast.Height; y++)
42 | {
43 | for (int x = 0; x < fast.Width; x++)
44 | {
45 | fast.SetPixel(x, y, expected);
46 | Color actual = fast.GetPixel(x, y);
47 |
48 | Assert.Equal(expected.ToArgb(), actual.ToArgb());
49 | }
50 | }
51 | }
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/ImageProcessor.Tests/ImageDeepCopyTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ImageProcessor.Tests
8 | {
9 | public class ImageDeepCopyTests
10 | {
11 | public void CanDeepCopyImage()
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tests/ImageProcessor.Tests/ImageExtensionTests.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using Xunit;
3 |
4 | namespace ImageProcessor.Tests
5 | {
6 | public class ImageExtensionTests
7 | {
8 | [Fact]
9 | public void CanDeepCloneRawImage()
10 | {
11 | using (var image = new Bitmap(10, 10))
12 | {
13 | Color expected = Color.HotPink;
14 | image.SetPixel(0, 0, expected);
15 |
16 | using (Bitmap copy = image.DeepClone())
17 | {
18 | Assert.True(image != copy);
19 |
20 | Color pixel = copy.GetPixel(0, 0);
21 | Assert.Equal(expected.ToArgb(), pixel.ToArgb());
22 | }
23 | }
24 | }
25 |
26 | // TODO: Per format tests.
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/ImageProcessor.Tests/ImageFactoryEncodingTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using ImageProcessor.Configuration;
3 | using ImageProcessor.Formats;
4 | using Xunit;
5 |
6 | namespace ImageProcessor.Tests
7 | {
8 | public class ImageFactoryEncodingTests
9 | {
10 | public ImageFactoryEncodingTests()
11 | {
12 | ImageProcessorBootstrapper.Instance.AddImageFormats(new WebPFormat());
13 | }
14 |
15 | private const string Category = "Encoding";
16 |
17 | public static IEnumerable