[
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\nbuild/\nbld/\n[Bb]in/\n[Oo]bj/\n\n# Enable \"build/\" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets\n!packages/*/build/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n#NUNIT\n*.VisualState.xml\nTestResult.xml\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding addin-in\n.JustCode\n\n# TeamCity is a build add-in\n# NuGet\n*.nuget.props\n*.nuget.targets\n\n**/packages/*\n!**/packages/build/\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Build results\n[Dd]ebug/\n[Rr]elease/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n/Deploy/Nuget/NuGet.exe\n"
  },
  {
    "path": "Deploy/Licence.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "Deploy/Nuget/Push.ps1",
    "content": "#--references: \n#  list files: https://medium.com/@victorleungtw/replace-text-in-xml-files-with-powershell-504d3e37a058\n\ntimeout /T 5\n\nWrite-Host\nWrite-Host Pushing packages:\n$files = @(Get-ChildItem *.nupkg -Recurse)\nforeach($f in $files)\n{\n   Write-Host $f\n   $cmd = './nuget push \"$f\" -source https://www.nuget.org/api/v2/package'\n   iex $cmd\n}\n\nWrite-Host\n#pause"
  },
  {
    "path": "Directory.Build.props",
    "content": "﻿<Project>\n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <LangVersion>preview</LangVersion>\n\t<OutputPath>bin\\</OutputPath>\n\t<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "DotImaging.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.29102.190\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Source\", \"Source\", \"{80058A54-6223-480C-AA19-F99E7AE593F3}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Samples\", \"Samples\", \"{05BDC895-7F7B-4B6F-8D69-E7916837092D}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Deploy\", \"Deploy\", \"{80FC5EA1-3478-4E7F-8B05-190DF6750EA4}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tDeploy\\Licence.txt = Deploy\\Licence.txt\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Logo\", \"Logo\", \"{817B040E-5F27-4ACD-B1E4-F46452668A0E}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tDeploy\\Logo\\DotImaging.pptx = Deploy\\Logo\\DotImaging.pptx\r\n\t\tDeploy\\Logo\\logo-big.png = Deploy\\Logo\\logo-big.png\r\n\t\tDeploy\\Logo\\logo-small.png = Deploy\\Logo\\logo-small.png\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Image.BitmapInterop\", \"Source\\BitmapInterop\\Image.BitmapInterop.csproj\", \"{CE222A84-B03B-4053-8BA4-F237063382F2}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Image\", \"Source\\Image\\Image.csproj\", \"{3CF8F155-3DA1-4529-9B28-D409E86ED4E2}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"IO\", \"Source\\IO\\IO.csproj\", \"{ED70A44E-9443-4A28-9B95-31299F8B2D08}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"IO.Web\", \"Source\\IO.Web\\IO.Web.csproj\", \"{B8404D66-B64E-43E0-9653-35FC6782072F}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.VideoStreaming\", \"Samples\\Sample.VideoStreaming\\Sample.VideoStreaming.csproj\", \"{CB088D8A-3438-4DB9-87C2-99425FE27F07}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.Basic\", \"Samples\\Sample.Basic\\Sample.Basic.csproj\", \"{5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.Interop\", \"Samples\\Sample.Interop\\Sample.Interop.csproj\", \"{E4ED626D-359B-493C-A72E-3738A5353D1B}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.Capture\", \"Samples\\Sample.Capture\\Sample.Capture.csproj\", \"{D0C18418-5282-4BA8-ABF7-CC2A9A179517}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.CaptureAndRecord\", \"Samples\\Sample.CaptureAndRecord\\Sample.CaptureAndRecord.csproj\", \"{867ED0BD-FBFB-4C0C-A34B-D71361874AA0}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.ImageExtractor\", \"Samples\\Sample.ImageExtractor\\Sample.ImageExtractor.csproj\", \"{55FF1668-9501-4007-84D8-26EF860F0D0D}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Sample.MultipleCameraCapture\", \"Samples\\Sample.MultipleCameraCapture\\Sample.MultipleCameraCapture.csproj\", \"{C30A145E-02FB-49B4-8F3E-6673AF9D121A}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"NuGet\", \"NuGet\", \"{44744CCA-2769-4607-AC90-78B6A11A2E77}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tDeploy\\Nuget\\Push.ps1 = Deploy\\Nuget\\Push.ps1\r\n\t\tDeploy\\Nuget\\UpdatePackageVersion.ps1 = Deploy\\Nuget\\UpdatePackageVersion.ps1\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"UI.Image\", \"Source\\UI.Image\\UI.Image.csproj\", \"{F021F056-59F7-4C49-9F0F-3BE6721F920F}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{7C2B92C2-DD93-47F5-8ADA-BF21086EDCDD}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tDirectory.Build.props = Directory.Build.props\r\n\t\tREADME.md = README.md\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Primitives2D\", \"Source\\Primitives2D\\Primitives2D.csproj\", \"{CF955F14-669D-4802-A3A3-0CDA7601205E}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tRelease|x64 = Release|x64\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{CE222A84-B03B-4053-8BA4-F237063382F2}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{CE222A84-B03B-4053-8BA4-F237063382F2}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{CE222A84-B03B-4053-8BA4-F237063382F2}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{CE222A84-B03B-4053-8BA4-F237063382F2}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{ED70A44E-9443-4A28-9B95-31299F8B2D08}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{ED70A44E-9443-4A28-9B95-31299F8B2D08}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{ED70A44E-9443-4A28-9B95-31299F8B2D08}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{ED70A44E-9443-4A28-9B95-31299F8B2D08}.Release|x64.Build.0 = Release|x64\r\n\t\t{B8404D66-B64E-43E0-9653-35FC6782072F}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{B8404D66-B64E-43E0-9653-35FC6782072F}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{B8404D66-B64E-43E0-9653-35FC6782072F}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{B8404D66-B64E-43E0-9653-35FC6782072F}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{CB088D8A-3438-4DB9-87C2-99425FE27F07}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{CB088D8A-3438-4DB9-87C2-99425FE27F07}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{CB088D8A-3438-4DB9-87C2-99425FE27F07}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{CB088D8A-3438-4DB9-87C2-99425FE27F07}.Release|x64.Build.0 = Release|x64\r\n\t\t{5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Release|x64.Build.0 = Release|x64\r\n\t\t{E4ED626D-359B-493C-A72E-3738A5353D1B}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{E4ED626D-359B-493C-A72E-3738A5353D1B}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{E4ED626D-359B-493C-A72E-3738A5353D1B}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{E4ED626D-359B-493C-A72E-3738A5353D1B}.Release|x64.Build.0 = Release|x64\r\n\t\t{D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Release|x64.Build.0 = Release|x64\r\n\t\t{867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Release|x64.Build.0 = Release|x64\r\n\t\t{55FF1668-9501-4007-84D8-26EF860F0D0D}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{55FF1668-9501-4007-84D8-26EF860F0D0D}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{55FF1668-9501-4007-84D8-26EF860F0D0D}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{55FF1668-9501-4007-84D8-26EF860F0D0D}.Release|x64.Build.0 = Release|x64\r\n\t\t{C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Release|x64.Build.0 = Release|x64\r\n\t\t{F021F056-59F7-4C49-9F0F-3BE6721F920F}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{F021F056-59F7-4C49-9F0F-3BE6721F920F}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{F021F056-59F7-4C49-9F0F-3BE6721F920F}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{F021F056-59F7-4C49-9F0F-3BE6721F920F}.Release|x64.Build.0 = Release|x64\r\n\t\t{CF955F14-669D-4802-A3A3-0CDA7601205E}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{CF955F14-669D-4802-A3A3-0CDA7601205E}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{CF955F14-669D-4802-A3A3-0CDA7601205E}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{CF955F14-669D-4802-A3A3-0CDA7601205E}.Release|x64.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(NestedProjects) = preSolution\r\n\t\t{817B040E-5F27-4ACD-B1E4-F46452668A0E} = {80FC5EA1-3478-4E7F-8B05-190DF6750EA4}\r\n\t\t{CE222A84-B03B-4053-8BA4-F237063382F2} = {80058A54-6223-480C-AA19-F99E7AE593F3}\r\n\t\t{3CF8F155-3DA1-4529-9B28-D409E86ED4E2} = {80058A54-6223-480C-AA19-F99E7AE593F3}\r\n\t\t{ED70A44E-9443-4A28-9B95-31299F8B2D08} = {80058A54-6223-480C-AA19-F99E7AE593F3}\r\n\t\t{B8404D66-B64E-43E0-9653-35FC6782072F} = {80058A54-6223-480C-AA19-F99E7AE593F3}\r\n\t\t{CB088D8A-3438-4DB9-87C2-99425FE27F07} = {05BDC895-7F7B-4B6F-8D69-E7916837092D}\r\n\t\t{5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A} = {05BDC895-7F7B-4B6F-8D69-E7916837092D}\r\n\t\t{E4ED626D-359B-493C-A72E-3738A5353D1B} = {05BDC895-7F7B-4B6F-8D69-E7916837092D}\r\n\t\t{D0C18418-5282-4BA8-ABF7-CC2A9A179517} = {05BDC895-7F7B-4B6F-8D69-E7916837092D}\r\n\t\t{867ED0BD-FBFB-4C0C-A34B-D71361874AA0} = {05BDC895-7F7B-4B6F-8D69-E7916837092D}\r\n\t\t{55FF1668-9501-4007-84D8-26EF860F0D0D} = {05BDC895-7F7B-4B6F-8D69-E7916837092D}\r\n\t\t{C30A145E-02FB-49B4-8F3E-6673AF9D121A} = {05BDC895-7F7B-4B6F-8D69-E7916837092D}\r\n\t\t{44744CCA-2769-4607-AC90-78B6A11A2E77} = {80FC5EA1-3478-4E7F-8B05-190DF6750EA4}\r\n\t\t{F021F056-59F7-4C49-9F0F-3BE6721F920F} = {80058A54-6223-480C-AA19-F99E7AE593F3}\r\n\t\t{CF955F14-669D-4802-A3A3-0CDA7601205E} = {80058A54-6223-480C-AA19-F99E7AE593F3}\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {DEAC2BC6-C697-4361-9909-CF7055FE9B05}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\r\n    <a href=\"https://www.nuget.org/profiles/dajuric\"> <img src=\"Deploy/Logo/logo-big.png\" alt=\"DotImaging logo\" width=\"120\" align=\"center\"> </a>\r\n</p>\r\n\r\n<p align=\"center\">\r\n    <a href=\"https://www.nuget.org/profiles/dajuric\"> <img src=\"https://img.shields.io/badge/NuGet-v5.2.0-blue.svg?style=flat-square\" alt=\"NuGet packages version\"/>  </a>\r\n</p>\r\n\r\n**DotImaging** - .NET array as imaging object  \r\nThe framework sets focus on .NET native array as primary imaging object, offers extensibility support via extensions, and provides unified platform-abstract imaging IO API. \r\n\r\n## News\r\n+ 5.2.0 version came out (19/02/2019)\r\n+ Image enchacement library for DotImaging: <a href=\"https://github.com/dajuric/dot-devignetting\">DotDevignetting</a>!\r\n\r\n## So why DotImaging ?\r\n\r\n+ Image as native .NET 2D array \r\n+ portable* \r\n+ lightweight\r\n+ extensions, extensions, extensions....\r\n\r\n*IO and Drawing assemlies depend on OpenCV\r\n\r\n## Libraries / NuGet packages\r\n\r\n\r\n###### Core\r\n\r\n+ <a href=\"https://www.nuget.org/packages/DotImaging.Image\"> \r\n    <img src=\"https://img.shields.io/badge/DotImaging-Image-red.svg?style=flat-square\" alt=\"DotImaging.Image\"/>  \r\n  </a> \r\n  .NET image array extensions. Color and depth conversions. Slim unmanaged structure for fast pixel manipulation.\r\n\r\n  > **Tutorial:** <a href=\"http://www.codeproject.com/Articles/829349/Introducing-Portable-Generic-Image-Library-for-Csh\" target=\"_blank\">Portable Generic Image</a>\r\n\r\n ``` csharp\r\n//convert to grayscale and flip\r\nBgr<byte>[,] image = ImageIO.LoadColor(\"sample.jpg\"); //IO package\r\nGray<byte>[,] grayIm = image.ToGray()\r\n                             .Flip(FlipDirection.Horizontal);\r\n\r\n//get the modified blue channel \r\nvar modifiedImage = image.AsEnumerable()\r\n\t                 .Select(x => x.B / 2)\r\n\t\t\t .ToArray2D(image.Size());\r\n ```\r\n\r\n+ <a href=\"https://www.nuget.org/packages/DotImaging.Primitives2D\"> \r\n    <img src=\"https://img.shields.io/badge/DotImaging-Primitives2D-red.svg?style=flat-square\" alt=\"DotImaging.Primitives2D\"/>  \r\n  </a> \r\n  Portable 2D drawing primitives (Extensions for Point, Size, Rectangle and additional primitives)\r\n\r\n###### IO\r\n\r\n+ <a href=\"https://www.nuget.org/packages/DotImaging.IO\"> \r\n    <img src=\"https://img.shields.io/badge/DotImaging-IO-red.svg?style=flat-square\" alt=\"DotImaging.IO\"/>  \r\n  </a>\r\n  A unified API for IO image access (camera, file, image directory). Portable image loading/saving.\r\n\r\n  > **Tutorial:** <a href=\"http://www.codeproject.com/Articles/828012/Introducing-Portable-Video-IO-Library-for-Csharp\" target=\"_blank\">Portable Imaging IO</a>\r\n\r\n ``` csharp\r\nvar reader = new FileCapture(\"sample.mp4\");\r\nreader.Open();\r\n\r\nBgr<byte>[,] frame = null;\r\nwhile(true)\r\n{\r\n       reader.ReadTo(ref frame);\r\n       if (frame == null)\r\n          break;\r\n\r\n       frame.Show(scaleForm: true); //UI package\r\n}\r\n\r\nreader.Close();\r\n ``` \r\n \r\n+ <a href=\"https://www.nuget.org/packages/DotImaging.IO.Web\"> \r\n    <img src=\"https://img.shields.io/badge/DotImaging-IO.Web-red.svg?style=flat-square\" alt=\"DotImaging.IO.Web\"/>  \r\n  </a>\r\n  Image or video download/streaming (direct video link or Youtube links).\r\n\r\n ``` csharp\r\n//------get an image from the Web\r\nnew Uri(\"http://vignette3.wikia.nocookie.net/disney/images/5/5d/Lena_headey_.jpg\")\r\n     .GetBytes().DecodeAsColorImage().Show(); //(Show - UI package)\r\n \r\n//------stream a video from Youtube\r\nvar pipeName = new Uri(\"https://www.youtube.com/watch?v=Vpg9yizPP_g\").NamedPipeFromYoutubeUri(); //Youtube\r\nvar reader = new FileCapture(String.Format(@\"\\\\.\\pipe\\{0}\", pipeName)) //IO package\r\n \r\n//... (regular stream reading - see IO package sample)\r\n ``` \r\n\r\n \r\n###### Interoperability\r\n\r\n+ <a href=\"https://www.nuget.org/packages/DotImaging.BitmapInterop\"> \r\n    <img src=\"https://img.shields.io/badge/DotImaging-BitmapInterop-red.svg?style=flat-square\" alt=\"DotImaging.BitmapInterop\"/>  \r\n  </a>\r\n  Interoperability extensions between .NET array and System.Drawing.Bitmap.\r\n\r\n ``` csharp\r\nvar image = new Gray<byte>[240, 320];\r\nvar bmp = image.ToBitmap(); //to Bitmap\r\n\r\nvar imageFromBmp = bmp.ToArray() as Bgr<byte>[,]; //from Bitmap\r\n ``` \r\n \r\n \r\n###### Extensions\r\n\r\n+ <a href=\"https://www.nuget.org/packages/DotImaging.UI.Image\"> \r\n    <img src=\"https://img.shields.io/badge/DotImaging-UIImage-red.svg?style=flat-square\" alt=\"DotImaging.UI\"/>  \r\n  </a> \r\n  Image preview dialog and drawing.\r\n\r\n ``` csharp\r\nBgr<byte>[,] image = new Bgr<byte>[480, 640];\r\nimage.Show(); //show image (non-blocking)\r\nimage.ShowDialog(); //show image (blocking)\r\n\r\n//draw something\r\nimage.Draw(new Rectangle(50, 50, 200, 100), Bgr<byte>.Red, -1);\r\nimage.Draw(new Circle(50, 50, 25), Bgr<byte>.Blue, 5);\r\n ```\r\n  \r\n## Getting started\r\n+ Just pick what you need. An appropriate readme file will be shown upon selected NuGet package installation. \r\n+ Samples\r\n\r\n## Final word\r\nIf you like the project please **star it** in order to help to spread the word. That way you will make the framework more significant and in the same time you will motivate me to improve it, so the benefit is mutual.\r\n"
  },
  {
    "path": "Samples/Sample.Basic/Program.cs",
    "content": "﻿using DotImaging;\nusing System.Drawing;\nusing System;\nusing System.IO;\n\nnamespace BasicImageOperations\n{\n    static class Program\n    {\n        static void Main()\n        {\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\n\n            //load from the Web\n            var image = new Uri(\"http://vignette3.wikia.nocookie.net/disney/images/5/5d/Lena_headey_.jpg\")\n                            .GetBytes()\n                            .DecodeAsColorImage();\n\n            //show image\n            image.Show(\"New Lena\");\n\n            //draw something\n            image.DrawRectangle(new Rectangle(50, 50, 200, 100), Bgr<byte>.Red, -1);\n            image.DrawText(\"Hello world!\", DotImaging.Font.Big, new Point(10, 100), Bgr<byte>.White);\n\n            //save and load\n            image.Save(\"out.png\");\n            ImageIO.LoadColor(\"out.png\").ShowDialog(\"Saved image\", autoSize: true);\n        }\n    }\n}\n"
  },
  {
    "path": "Samples/Sample.Basic/Sample.Basic.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <OutputType>Exe</OutputType>\n    <Platforms>x64</Platforms>\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\BitmapInterop\\Image.BitmapInterop.csproj\" />\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n    <ProjectReference Include=\"..\\..\\Source\\IO.Web\\IO.Web.csproj\" />\n\t  <ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t  <ProjectReference Include=\"..\\..\\Source\\UI.Image\\UI.Image.csproj\" />\n  </ItemGroup> \n</Project>\n"
  },
  {
    "path": "Samples/Sample.Capture/Program.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing DotImaging;\r\nusing System;\r\nusing System.IO;\r\n\r\nnamespace Capture\r\n{\r\n    class Program\r\n    {\r\n        [STAThread]\r\n        static void Main()\r\n        {\r\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\r\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\r\n\r\n            Console.WriteLine(\"Press ESC to stop playing\");\r\n\r\n            //var reader = new CameraCapture(0); //capture from camera\r\n            //(reader as CameraCapture).FrameSize = new Size(640, 480);\r\n\r\n            var reader = new FileCapture(Path.Combine(getResourceDir(), \"Welcome.mp4\")); //capture from video\r\n            //var reader = new ImageDirectoryCapture(Path.Combine(getResourceDir(), \"Sequence\"), \"*.jpg\");\r\n            reader.Open();\r\n    \r\n            Bgr<byte>[,] frame = null;\r\n            do\r\n            {\r\n                reader.ReadTo(ref frame);\r\n                if (frame == null)\r\n                    break;\r\n\r\n                frame.Show(autoSize: true);\r\n            }\r\n            while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape));\r\n\r\n            reader.Dispose();\r\n            ImageUI.CloseAll();\r\n        }\r\n\r\n        private static string getResourceDir()\r\n        {\r\n            return Path.Combine(new DirectoryInfo(Environment.CurrentDirectory).FullName, \"Resources\");\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Samples/Sample.Capture/Sample.Capture.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <Platforms>x64</Platforms>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>DotImaging</RootNamespace>\n    <OutputPath>bin\\</OutputPath>\n    <ApplicationIcon />\n    <OutputType>Exe</OutputType>\n    <StartupObject />\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\UI.Image\\UI.Image.csproj\" />\n  </ItemGroup>\n    \n  <ItemGroup>\n    <None Update=\"Resources\\Welcome.mp4\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n  </ItemGroup> \n</Project>\n"
  },
  {
    "path": "Samples/Sample.CaptureAndRecord/Program.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2016\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing DotImaging;\nusing System;\nusing System.IO;\n\nnamespace CaptureAndRecording\n{\n    static class Program\n    {\n        static void Main()\n        {\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\n\n            //var reader = new CameraCapture(0); //capture from camera\n            var reader = new FileCapture(Path.Combine(getResourceDir(), \"Welcome.mp4\"));\n           reader.Open();\n\n           var writer = new VideoWriter(@\"output.avi\", reader.FrameSize, /*reader.FrameRate does not work Cameras*/ 30); //TODO: bug: FPS does not work for cameras\n           writer.Open();\n\n            Bgr<byte>[,] frame = null;\n            do\n            {\n                reader.ReadTo(ref frame);\n                if (frame == null)\n                    break;\n\n                using (var uFrame = frame.Lock())\n                { writer.Write(uFrame); }\n\n                frame.Show(autoSize: true);\n            }\n            while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape));\n\n            reader.Dispose();\n            writer.Dispose();\n\n            ImageUI.CloseAll();\n        }\n\n        private static string getResourceDir()\n        {\n            return Path.Combine(new DirectoryInfo(Environment.CurrentDirectory).FullName, \"Resources\");\n        }\n    }\n}\n"
  },
  {
    "path": "Samples/Sample.CaptureAndRecord/Sample.CaptureAndRecord.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <Platforms>x64</Platforms>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>DotImaging</RootNamespace>\n    <OutputPath>bin\\</OutputPath>\n    <ApplicationIcon />\n    <OutputType>Exe</OutputType>\n    <StartupObject />\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\UI.Image\\UI.Image.csproj\" />\n  </ItemGroup>\n    \n  <ItemGroup>\n    <None Update=\"Resources\\Welcome.mp4\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n  </ItemGroup> \n</Project>\n"
  },
  {
    "path": "Samples/Sample.ImageExtractor/Program.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2016\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing DotImaging;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\nnamespace ImageExtractor\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\n\n            //emulate input args\n            string fileMask = Path.Combine(getResourceDir(), \"Welcome.mp4\");\n\n            if (args.Length == 1)\n                fileMask = args[0];\n\n            var fileNames = enumerateFiles(fileMask);\n            foreach (var fileName in fileNames)\n            {\n                extractVideo(fileName);\n            }\n        }\n\n        private static void extractVideo(string fileName)\n        {\n            //get output dir (same as file name and in the same folder as video)\n            var fileInfo = new FileInfo(fileName);\n            var fileNameNoExt = fileInfo.Name.Replace(fileInfo.Extension, String.Empty);\n            string outputDir = Path.Combine(fileInfo.DirectoryName, fileNameNoExt);\n\n            //open video\n            var reader = new FileCapture(fileName);\n            reader.Open();\n\n            reader.SaveFrames(outputDir, \"{0}.jpg\", p => Console.Write($\"\\rExtracting: {(int)(p * 100)} %\"));\n            ImageUI.CloseAll();\n        }\n\n        private static IEnumerable<string> enumerateFiles(string fileMask)\n        {\n            var pathDelimiter = Path.DirectorySeparatorChar;\n\n            fileMask = normalizePathDelimiters(fileMask, pathDelimiter.ToString());\n            string fileMaskWithoutPath = fileMask.Split(pathDelimiter).Last();\n            string path = fileMask.Replace(fileMaskWithoutPath, String.Empty);\n\n            var fileNames = Directory.EnumerateFiles(path, fileMaskWithoutPath);\n            return fileNames;\n        }\n\n        private static string getResourceDir()\n        {\n            return Path.Combine(new DirectoryInfo(Environment.CurrentDirectory).FullName, \"Resources\");\n        }\n\n        private static string normalizePathDelimiters(string path, string normalizedDelimiter) //TODO: replace with extension when available\n        {\n            return path.Replace(\"//\", normalizedDelimiter)\n                       .Replace(@\"\\\", normalizedDelimiter)\n                       .Replace(@\"\\\\\", normalizedDelimiter)\n                       .Replace(@\"/\", normalizedDelimiter);\n        }\n    }\n}\n"
  },
  {
    "path": "Samples/Sample.ImageExtractor/Sample.ImageExtractor.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <Platforms>x64</Platforms>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>DotImaging</RootNamespace>\n    <OutputPath>bin\\</OutputPath>\n    <ApplicationIcon />\n    <OutputType>Exe</OutputType>\n    <StartupObject />\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\UI.Image\\UI.Image.csproj\" />\n  </ItemGroup>\n    \n  <ItemGroup>\n    <None Update=\"Resources\\Welcome.mp4\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n  </ItemGroup> \n</Project>\n"
  },
  {
    "path": "Samples/Sample.Interop/Program.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2016\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing DotImaging;\nusing System;\nusing System.IO;\n\nnamespace GenericImageInteropDemo\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\n\n            var img = new Bgr<byte>[480, 640];\n\n            //***********************************************************************************************************************************************************************\n            Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(\"********* TColor[,] <=> Image<> conversions (built-in) ****************\"); Console.ResetColor();\n            //to Image<>\n            Image<Bgr<byte>> lockedImg = img.Lock();\n            //from Image<>\n            var arr = lockedImg.Clone();\n\n            //***********************************************************************************************************************************************************************\n            Console.WriteLine();\n            Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(\"********* Image<,> <=> OpenCV conversions (built-in) ****************\"); Console.ResetColor();\n            //to IplImage\n            IplImage iplImage;\n            using (var uImg = img.Lock())\n            {\n                iplImage = uImg.AsCvIplImage(); //data is shared\n            }\n            //from IplImage\n            var imgFromIpl = iplImage.AsImage(); \n\n            //***********************************************************************************************************************************************************************\n            Console.WriteLine();\n            Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(\"*********** Image<,> <=> Bitmap conversions (BitmapInterop) ****************\"); Console.ResetColor();\n            //to Bitmap\n            var bmp = img.ToBitmap();\n            //from Bitmap\n            var imgFromBmp = bmp.ToImage<Bgr<byte>>();\n        }\n    }\n}\n"
  },
  {
    "path": "Samples/Sample.Interop/Sample.Interop.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <Platforms>x64</Platforms>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>DotImaging</RootNamespace>\n    <OutputPath>bin\\</OutputPath>\n    <ApplicationIcon />\n    <OutputType>Exe</OutputType>\n    <StartupObject />\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\BitmapInterop\\Image.BitmapInterop.csproj\" />\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\UI.Image\\UI.Image.csproj\" />\n  </ItemGroup> \n \n</Project>\n"
  },
  {
    "path": "Samples/Sample.MultipleCameraCapture/Program.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2016\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing DotImaging;\nusing System.Collections.Generic;\nusing System.IO;\n\nnamespace MultipleCameraCapture\n{\n    static class Program\n    {\n        static void Main()\n        {\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\n\n            Console.WriteLine(\"Press ESC to stop playing\");\n\n            List<CameraCapture> captures = new List<CameraCapture>();\n\n            var cameraCount = CameraCapture.CameraCount;\n            if (cameraCount == 0)\n            {\n                Console.WriteLine(\"No camera device is present.\");\n                return;\n            }\n\n            //initialize\n            for (int camIdx = 0; camIdx < cameraCount; camIdx++)\n            {\n                var cap = new CameraCapture(camIdx);\n                cap.Open();\n\n                captures.Add(cap);\n            }\n\n            //grab frames\n            Bgr<byte>[][,] frames = new Bgr<byte>[cameraCount][,];\n            do\n            {\n                for (int camIdx = 0; camIdx < cameraCount; camIdx++)\n                {\n                    captures[camIdx].ReadTo(ref frames[camIdx]);\n                    if (frames[camIdx] == null)\n                        break;\n\n                    frames[camIdx].Show(String.Format(\"Camera {0}\", camIdx), autoSize: true);\n                }\n            }\n            while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape));\n\n            //dispose\n            captures.ForEach(x => x.Dispose());\n            ImageUI.CloseAll();\n        }\n    }\n}\n"
  },
  {
    "path": "Samples/Sample.MultipleCameraCapture/Sample.MultipleCameraCapture.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <Platforms>x64</Platforms>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>DotImaging</RootNamespace>\n    <OutputPath>bin\\</OutputPath>\n    <ApplicationIcon />\n    <OutputType>Exe</OutputType>\n    <StartupObject />\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\UI.Image\\UI.Image.csproj\" />\n  </ItemGroup> \n</Project>\n"
  },
  {
    "path": "Samples/Sample.UI/Program.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2016\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing DotImaging;\nusing DotImaging.Linq;\nusing System.Linq;\nusing System;\nusing System.Threading;\nusing System.IO;\n\nnamespace UIDemo\n{\n    class Program\n    {\n        [STAThread]\n        static void Main(string[] args)\n        {\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\n\n            //select color\n            Bgr<byte>[,] image = new Bgr<byte>[480, 640];\n            Hsv<byte> color = UI.PickColor(Bgr<byte>.Red).ToHsv();\n\n            //select mask\n            Gray<byte>[,] mask = image.GetMask();\n            if (mask.AsEnumerable().Sum(x => x.Intensity) == 0) //if the mask is empty\n                mask.SetValue<Gray<byte>>(Byte.MaxValue);\n\n            //increase saturation incrementally\n            for (int s = 0; s <= Byte.MaxValue; s++)\n            {\n                color.S = (byte)s;\n                image.SetValue<Bgr<byte>>(color.ToBgr(), mask);\n\n                image.Show(scaleForm: true);\n                ((double)s / Byte.MaxValue).Progress(message: \"Changing saturation\");\n\n                Thread.Sleep(50);\n            }\n\n            //save last image\n            string fileName = UI.SaveImage();\n            if (fileName != null) image.Save(fileName);\n\n            //close all\n            UI.CloseAll();\n        }\n    }\n}\n"
  },
  {
    "path": "Samples/Sample.UI/Sample.UI.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>net47</TargetFrameworks>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>DotImaging</RootNamespace>\n    <OutputPath>bin\\</OutputPath>\n    <ApplicationIcon />\n    <OutputType>Exe</OutputType>\n    <StartupObject />\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n    <ProjectReference Include=\"..\\..\\Source\\LINQ\\Linq.csproj\" />\n    <ProjectReference Include=\"..\\..\\Source\\Primitives2D\\Primitives2D.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\UI\\UI.csproj\" />\n  </ItemGroup> \n</Project>\n"
  },
  {
    "path": "Samples/Sample.VideoStreaming/Program.cs",
    "content": "﻿using DotImaging;\nusing System;\nusing System.Diagnostics;\nusing System.IO;\n\nnamespace YoutubeStreaming\n{\n    class Program\n    {\n        public static void Main()\n        {\n            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);\n            Environment.SetEnvironmentVariable(\"PATH\", Environment.GetEnvironmentVariable(\"PATH\") + \";runtimes/win10-x64/\"); //only needed if projects are directly referenced\n\n\n            var sourceName = String.Empty;\n\n            //video over pipe (direct link and Youtube) (do not support seek)\n            //var pipeName = new Uri(\"http://trailers.divx.com/divx_prod/divx_plus_hd_showcase/BigBuckBunny_DivX_HD720p_ASP.divx\").NamedPipeFromVideoUri(); //web-video\n            var pipeName = new Uri(\"https://www.youtube.com/watch?v=Vpg9yizPP_g\").NamedPipeFromYoutubeUri(); //Youtube\n            sourceName = String.Format(@\"\\\\.\\pipe\\{0}\", pipeName);\n\n            //video http link (Supports seek)\n            //sourceName = \"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4\";\n\n            //---------------------------------------------\n            ImageStreamReader reader = new FileCapture(sourceName);\n            reader.Open();\n\n            //seek if you can\n            if(reader.CanSeek)\n                reader.Seek((int)(reader.Length * 0.25), System.IO.SeekOrigin.Begin);\n\n            //read video frames\n            Bgr<byte>[,] frame = null;\n            while(true)\n            {\n                reader.ReadTo(ref frame);\n                if (frame == null)\n                    break;\n\n                frame.Show(autoSize: false);\n                Console.Write($\"\\r Received: {reader.Position * 100 / reader.Length}%\");\n            }\n            Console.WriteLine(\"The end.\");\n\n            //---------------------------------------------------------------------------\n            ImageUI.CloseAll();\n            Console.WriteLine(\"Downloading video...\");\n\n            string fileExtension;\n            var downloadPipeName = new Uri(\"https://www.youtube.com/watch?v=Vpg9yizPP_g\").NamedPipeFromYoutubeUri(out fileExtension); //Youtube\n\n            downloadPipeName.SaveNamedPipeStream(\"out\" + fileExtension);\n            Console.WriteLine(\"Video saved.\");\n            Process.Start(\"out\" + fileExtension); //open local file\n        }\n    }\n}\n"
  },
  {
    "path": "Samples/Sample.VideoStreaming/Sample.VideoStreaming.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <Platforms>x64</Platforms>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>DotImaging</RootNamespace>\n    <OutputPath>bin\\</OutputPath>\n    <ApplicationIcon />\n    <OutputType>Exe</OutputType>\n    <StartupObject />\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Source\\Image\\Image.csproj\" />\n    <ProjectReference Include=\"..\\..\\Source\\IO.Web\\IO.Web.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\IO\\IO.csproj\" />\n\t<ProjectReference Include=\"..\\..\\Source\\UI.Image\\UI.Image.csproj\" />\n  </ItemGroup> \n</Project>\n"
  },
  {
    "path": "Source/BitmapInterop/.nuSpec/readmeImage.Bitmap.txt",
    "content": "﻿Provides extensions for interoperability with System.Drawing.Bitmap, Point, PointF, Color and drawing extensions.\n\n1) Array <-> Bitmap conversion:\n\n\tvar image = new Gray<byte>[240, 320];\n\tvar bmp = image.ToBitmap();\n\n\tvar imageFromBmp = bmp.ToArray() as Bgr<byte>[,]; \n\n2) System.Drawing.Color <-> DotImaging color conversion:\n\n\tvar aquaColor = System.Drawing.Color.Aqua.ToBgr();\n\n\n3) Save bitmap with quality selection\n\t\n\tvar bmp = Bitmap.FromFile(\"sample.bmp\");\n\tbmp.Save(\"compressed.jpg\", 85);\n\n\nDiscover more extensions as you type :)"
  },
  {
    "path": "Source/BitmapInterop/BmpExtensions/BitmapConversion.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Imaging;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides conversion extension methods between generic image and <see cref=\"System.Drawing.Bitmap\"/>.\n    /// </summary>\n    public static class BitmapConversionExtensions\n    {\n        #region Conversion from Bitmap\n\n        static Dictionary<Type, PixelFormat> mapingTable = new Dictionary<Type, PixelFormat>\n        {\n            { typeof(Gray<byte>),  PixelFormat.Format8bppIndexed },\n            { typeof(Gray<short>), PixelFormat.Format16bppGrayScale },\n            { typeof(Bgr<byte>),   PixelFormat.Format24bppRgb },\n            { typeof(Bgra<byte>),  PixelFormat.Format32bppArgb },\n            { typeof(Bgr<short>),  PixelFormat.Format48bppRgb },\n            { typeof(Bgra<short>), PixelFormat.Format64bppArgb },\n        };\n\n        /// <summary>\n        /// Converts a bitmap to an image (copies data). \n        /// </summary>\n        /// <param name=\"bmp\">Input bitmap.</param>\n        /// <typeparam name=\"TColor\">Target color type.</typeparam>\n        /// <returns>2D array.</returns>\n        public static TColor[,] ToImage<TColor>(this Bitmap bmp)\n            where TColor: unmanaged, IColor\n        {\n            if (mapingTable.TryGetValue(typeof(TColor), out var targetPixelFmt) == false)\n                throw new NotSupportedException(\"Target mapping not found.\");\n\n            TColor[,] arr = null;\n            using (Bitmap targetBmp = bmp.Clone(new Rectangle(0, 0, bmp.Width, bmp.Height), targetPixelFmt))\n            {\n                var bmpData = targetBmp.LockBits(ImageLockMode.ReadOnly);\n                arr = new TColor[targetBmp.Height, targetBmp.Width];\n\n                using (var img = arr.Lock())\n                {\n                    Copy.UnsafeCopy2D(bmpData.Scan0, img.ImageData, bmpData.Stride, img.Stride, bmpData.Height);\n                }\n\n                targetBmp.UnlockBits(bmpData);\n            }\n\n            return arr;\n        }\n\n        #endregion\n\n        #region Conversion To Bitmap\n\n        private static Bitmap toBitmap(IImage img, PixelFormat pixelFormat)\n        {\n            var bmp = new Bitmap(img.Width, img.Height, pixelFormat);\n            var bmpData = bmp.LockBits(ImageLockMode.WriteOnly);\n            Copy.UnsafeCopy2D(img.ImageData, bmpData.Scan0, img.Stride, bmpData.Stride, bmpData.Height);\n            bmp.UnlockBits(bmpData);\n\n            if (pixelFormat == PixelFormat.Format8bppIndexed)\n                bmp.SetGrayscalePalette();\n\n            return bmp;\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Image<Gray<byte>> img)\n        {\n            return toBitmap(img, PixelFormat.Format8bppIndexed);\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Image<Gray<short>> img)\n        {\n            return toBitmap(img, PixelFormat.Format16bppGrayScale);\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Image<Bgr<byte>> img)\n        {\n            return toBitmap(img, PixelFormat.Format24bppRgb);\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Image<Bgra<byte>> img)\n        {\n            return toBitmap(img, PixelFormat.Format32bppArgb);\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Image<Bgr<short>> img)\n        {\n            return toBitmap(img, PixelFormat.Format48bppRgb);\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Image<Bgra<short>> img)\n        {\n            return toBitmap(img, PixelFormat.Format64bppArgb);\n        }\n\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Gray<byte>[,] img)\n        {\n            Bitmap bmp = null;\n            using (var uImg = img.Lock())\n            {\n                bmp = toBitmap(uImg, PixelFormat.Format8bppIndexed); \n            }\n            return bmp;\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Gray<short>[,] img)\n        {\n            Bitmap bmp = null;\n            using (var uImg = img.Lock())\n            {\n                bmp = toBitmap(uImg, PixelFormat.Format16bppGrayScale);\n            }\n            return bmp;\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Bgr<byte>[,] img)\n        {\n            Bitmap bmp = null;\n            using (var uImg = img.Lock())\n            {\n                bmp = toBitmap(uImg, PixelFormat.Format24bppRgb);\n            }\n            return bmp;\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Bgra<byte>[,] img)\n        {\n            Bitmap bmp = null;\n            using (var uImg = img.Lock())\n            {\n                bmp = toBitmap(uImg, PixelFormat.Format32bppArgb);\n            }\n            return bmp;\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Bgr<short>[,] img)\n        {\n            Bitmap bmp = null;\n            using (var uImg = img.Lock())\n            {\n                bmp = toBitmap(uImg, PixelFormat.Format48bppRgb);\n            }\n            return bmp;\n        }\n\n        /// <summary>\n        /// Converts an image to an bitmap.\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap ToBitmap(this Bgra<short>[,] img)\n        {\n            Bitmap bmp = null;\n            using (var uImg = img.Lock())\n            {\n                bmp = toBitmap(uImg, PixelFormat.Format64bppArgb);\n            }\n            return bmp;\n        }\n\n        #endregion\n\n        #region Cast to Bitmap\n\n        private static Bitmap asBitmap(IImage img, PixelFormat pixelFormat)\n        {\n            var bmp = new Bitmap(img.Width, img.Height, img.Stride, pixelFormat, img.ImageData);\n\n            if (pixelFormat == PixelFormat.Format8bppIndexed)\n                bmp.SetGrayscalePalette();\n\n            return bmp;\n        }\n\n        /// <summary>\n        /// Casts an image to an bitmap.\n        /// <para>Notice that GDI+ does not support bitmaps which stride is not 4.</para>\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap AsBitmap(this Image<Gray<byte>> img)\n        {\n            return asBitmap(img, PixelFormat.Format8bppIndexed);\n        }\n\n        /// <summary>\n        /// Casts an image to an bitmap.\n        /// <para>Notice that GDI+ does not support bitmaps which stride is not 4.</para>\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap AsBitmap(this Image<Gray<short>> img)\n        {\n            return asBitmap(img, PixelFormat.Format16bppGrayScale);\n        }\n\n        /// <summary>\n        /// Casts an image to an bitmap.\n        /// <para>Notice that GDI+ does not support bitmaps which stride is not 4.</para>\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap AsBitmap(this Image<Bgr<byte>> img)\n        {\n            return asBitmap(img, PixelFormat.Format24bppRgb);\n        }\n\n        /// <summary>\n        /// Casts an image to an bitmap.\n        /// <para>Notice that GDI+ does not support bitmaps which stride is not 4.</para>\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap AsBitmap(this Image<Bgra<byte>> img)\n        {\n            return asBitmap(img, PixelFormat.Format32bppArgb);\n        }\n\n        /// <summary>\n        /// Casts an image to an bitmap.\n        /// <para>Notice that GDI+ does not support bitmaps which stride is not 4.</para>\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap AsBitmap(this Image<Bgr<short>> img)\n        {\n            return asBitmap(img, PixelFormat.Format48bppRgb);\n        }\n\n        /// <summary>\n        /// Casts an image to an bitmap.\n        /// <para>Notice that GDI+ does not support bitmaps which stride is not 4.</para>\n        /// </summary>\n        /// <param name=\"img\">Input image.</param>\n        /// <returns>Bitmap</returns>\n        public static Bitmap AsBitmap(this Image<Bgra<short>> img)\n        {\n            return asBitmap(img, PixelFormat.Format64bppArgb);\n        }\n\n        #endregion\n\n        #region Misc\n \n        /// <summary>\n        /// Replaces color palette entries with grayscale intensities (256 entries).\n        /// </summary>\n        /// <param name=\"image\">The 8-bpp grayscale image.</param>\n        public static void SetGrayscalePalette(this Bitmap image)\n        {\n            if (image.PixelFormat != PixelFormat.Format8bppIndexed)\n                throw new ArgumentException(\"The provided image must have 8bpp pixel format.\");\n\n            var palette = image.Palette;\n            for (int i = 0; i < (Byte.MaxValue + 1); i++)\n            {\n                palette.Entries[i] = Color.FromArgb(i, i, i);\n            }\n\n            image.Palette = palette;\n        }\n\n        /// <summary>\n        /// Lock a <see cref=\"System.Drawing.Bitmap\"/> into system memory.\n        /// </summary>\n        /// <param name=\"bmp\">Bitmap to lock.</param>\n        /// <param name=\"imageLockMode\">Specifies the access level.</param>\n        /// <returns>Bitmap data.</returns>\n        public static BitmapData LockBits(this Bitmap bmp, ImageLockMode imageLockMode = ImageLockMode.ReadWrite)\n        {\n            return bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), imageLockMode, bmp.PixelFormat);\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Source/BitmapInterop/BmpExtensions/BmpIO.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Collections.Generic;\nusing System.Drawing.Imaging;\nusing System.IO;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Bitmap file save extensions.\n    /// </summary>\n    public static class BmpIO\n    {\n        static Dictionary<string, ImageCodecInfo> codecs = null;\n\n        static BmpIO()\n        {\n            codecs = new Dictionary<string, ImageCodecInfo>();\n\n            codecs.Add(\".jpg\", getEncoder(ImageFormat.Jpeg));\n            codecs.Add(\".jpeg\", getEncoder(ImageFormat.Jpeg));\n            codecs.Add(\".png\", getEncoder(ImageFormat.Png));\n        }\n\n        private static ImageCodecInfo getEncoder(ImageFormat format)\n        {\n            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();\n\n            foreach (ImageCodecInfo codec in codecs)\n            {\n                if (codec.FormatID == format.Guid)\n                {\n                    return codec;\n                }\n            }\n            return null;\n        }\n\n\n        /// <summary>\n        /// Saves the specified image.\n        /// <para>\n        /// Quality parameter is only supported for JPEG, PNG file types. \n        /// For other file types this value is omitted.\n        /// </para>\n        /// </summary>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"targetStream\">Target stream.</param>\n        /// <param name=\"imageFormat\">Image format.</param>\n        /// <param name=\"quality\">Quality parameter [0..100] where 0 means maximum compression.</param>\n        public static void Save(this System.Drawing.Image image, Stream targetStream, ImageFormat imageFormat, int quality = 90)\n        {\n            var encoder = getEncoder(imageFormat);\n\n            if (encoder != null)\n            {\n                System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;\n                EncoderParameters myEncoderParameters = new EncoderParameters(1);\n                myEncoderParameters.Param[0] = new EncoderParameter(myEncoder, quality);\n\n                image.Save(targetStream, encoder, myEncoderParameters);\n            }\n            else\n            {\n                image.Save(targetStream, imageFormat);\n            }\n        }\n\n\n        /// <summary>\n        /// Saves the specified image.\n        /// <para>\n        /// Quality parameter is only supported for JPEG, PNG file types. \n        /// For other file types this value is omitted.\n        /// </para>\n        /// </summary>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"filename\">File name.</param>\n        /// <param name=\"quality\">Quality parameter [0..100] where 0 means maximum compression.</param>\n        public static void Save(this System.Drawing.Image image, string filename, int quality = 90)\n        {\n            codecs.TryGetValue(new FileInfo(filename).Extension, out ImageCodecInfo codec);\n            if (codec == null)\n            {\n                image.Save(filename);\n                return;\n            }\n\n            System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;\n            EncoderParameters myEncoderParameters = new EncoderParameters(1);\n            myEncoderParameters.Param[0] = new EncoderParameter(myEncoder, quality);\n\n            image.Save(filename, codec, myEncoderParameters);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/BitmapInterop/BmpExtensions/ColorConversion.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Contains color format conversion extensions.\n    /// </summary>\n    public static class ColorConversion\n    {\n        /// <summary>\n        /// Gets System.Drawing.Color from Bgr8 color.\n        /// </summary>\n        /// <param name=\"color\">Color.</param>\n        /// <param name=\"opacity\">Opacity. If color has 4 channels opacity is discarded.</param>\n        /// <returns>System.Drawing.Color</returns>\n        public static System.Drawing.Color ToColor(this Gray<byte> color, byte opacity = Byte.MaxValue)\n        {\n            return Color.FromArgb(opacity, color.Intensity, color.Intensity, color.Intensity);\n        }\n\n        /// <summary>\n        /// Gets System.Drawing.Color from Bgr8 color.\n        /// </summary>\n        /// <param name=\"color\">Color.</param>\n        /// <param name=\"opacity\">Opacity. If color has 4 channels opacity is discarded.</param>\n        /// <returns>System.Drawing.Color</returns>\n        public static System.Drawing.Color ToColor(this Bgr<byte> color, byte opacity = Byte.MaxValue)\n        {\n            return Color.FromArgb(opacity, color.R, color.G, color.B);\n        }\n\n        /// <summary>\n        /// Gets System.Drawing.Color from Bgra8 color.\n        /// </summary>\n        /// <param name=\"color\">Color.</param>\n        /// <returns>System.Drawing.Color</returns>\n        public static System.Drawing.Color ToColor(this Bgra<byte> color)\n        {\n            return Color.FromArgb(color.A, color.R, color.G, color.B);\n        }\n\n        /// <summary>\n        /// Converts (casts) the color into 32-bit BGR color.\n        /// </summary>\n        /// <param name=\"color\">Color.</param>\n        /// <returns>Bgr representation.</returns>\n        public static Bgr<byte> ToBgr(this System.Drawing.Color color)\n        {\n            return new Bgr<byte> { B = color.B, G = color.G, R = color.R };\n        }\n    }\n}\n"
  },
  {
    "path": "Source/BitmapInterop/Image.BitmapInterop.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <AssemblyName>DotImaging.BitmapInterop</AssemblyName>\n    <RootNamespace>DotImaging</RootNamespace>\n    <Platforms>AnyCPU</Platforms>\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <PackageReference Include=\"System.Drawing.Common\" Version=\"4.5.1\" />\n    <ProjectReference Include=\"..\\Image\\Image.csproj\" />\n  </ItemGroup> \n\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <DocumentationFile>bin\\DotImaging.BitmapInterop.xml</DocumentationFile>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n  </PropertyGroup>\n\n\n  <!-- NuGet -->\n  <PropertyGroup>\n    <Version>5.3.0</Version>\n\n    <PackageId>DotImaging.BitmapInterop</PackageId>\n    <Description>Extensions for interoperability with System.Drawing.Bitmap.</Description>\n    <PackageTags>imaging interoperability extensions, GDI</PackageTags>\n\n    <Authors>Darko Jurić</Authors>\n    <Copyright>Darko Jurić</Copyright>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt</PackageLicenseUrl>\n    <PackageIconUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png</PackageIconUrl>\n    <PackageProjectUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</PackageProjectUrl>\n    <RepositoryUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</RepositoryUrl>\n\n    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    <PackageOutputPath>../../Deploy/NuGet/bin/</PackageOutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\".nuSpec\\readmeImage.Bitmap.txt\">\n      <PackagePath>Readme.txt</PackagePath>\n    </Content>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/IO/.nuSpec/readmeIO.txt",
    "content": "﻿Unified stream-like platform-abstract API for IO video access: web-camera support, various video-format reading / writing, image-directory reader.\nImage loading/saving (file or in-memory).\n\n1) image loading / saving:\n\n   Bgr<byte>[,] image = ImageIO.LoadColor(\"sample.jpg\"); //load Bgr color image\n   Gray<float>[,] hdrImage = (ImageIO.LoadUnchanged(\"hdrImage.png\") as Image<Gray<float>>).Clone(); //load HDR grayscale (or any other) image\n   image.Save(\"image.png\");\n\n\n2) image in-memory encoding / decoding\n\n   Bgr<byte>[,] bgrIm = ImageIO.LoadColor(\"sample.jpg\");\n   byte[] encodedBgr = bgrIm.EncodeAsJpeg(); //or png, bmp\n   Bgr<byte>[,] decodedBgr = encodedBgr.DecodeAsColorImage();\n\n\n3) media (camera, video, image-directory) capture:\n\n   ImageStreamReader reader = new CameraCapture(); //use specific class for device-specific properties (e.g. exposure, image name, ...)\n   reader.Open();\n\n   //read single frame\n   var frame = reader.Read().ToBgr();\n   reader.Close();\n   \n\n4) video writer:\n\n   ImageStreamWriter videoWriter = new VideoWriter(\"out.avi\", new Size(1280, 1024));\n\n   var image = new Bgr<byte>[1024, 1280];\n   videoWriter.Write(image.Lock()); //write a single frame\n\n   videoWriter.Close();\n\n5) frame extraction:\n\n\tvar reader = new FileCapture(fileName);\n    reader.Open();\n\n    reader.SaveFrames(outputDir, \"{0}.jpg\", (percentage) =>\n    {\n        ((double)percentage).Progress(message: \"Extracting video...\");\n    });\n\n\treader.Close();\n\n\nDiscover more types as you type :)\n\n\n"
  },
  {
    "path": "Source/IO/Base/Abstract/ImageStream.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Provides the base class for the image stream.\r\n    /// </summary>\r\n    /// <typeparam name=\"TImage\">Image type.</typeparam>\r\n    public abstract class ImageStream<TImage>: IDisposable\r\n    {\r\n        /// <summary>\r\n        /// Initializes a new instance of <see cref=\"ImageStream{TImage}\"/>.\r\n        /// </summary>\r\n        protected ImageStream()\r\n        {\r\n            this.CanSeek = false;\r\n            this.IsLiveStream = false;\r\n        }\r\n\r\n       /// <summary>\r\n       /// When overridden in a derived class, gets the length in number of frames.\r\n       /// </summary>\r\n        public abstract long Length { get; }\r\n\r\n        /// <summary>\r\n        /// When overridden in a derived class, gets the next frame index.\r\n        /// </summary>\r\n        public virtual long Position { get; protected set; }\r\n\r\n        /// <summary>\r\n        /// Gets whether the stream is live stream meaning that its length is not constant.\r\n        /// Those streams are usually not seek-able. See also: <see cref=\"CanSeek\"/>.\r\n        /// </summary>\r\n        public virtual bool IsLiveStream { get; protected set; }\r\n\r\n        /// <summary>\r\n        /// Gets a value indicating whether the current stream supports seeking.\r\n        /// </summary>\r\n        public virtual bool CanSeek { get; protected set; }\r\n\r\n        /// <summary>\r\n        /// When overridden in a derived class, sets the position within the current stream.\r\n        /// </summary>\r\n        /// <param name=\"offset\">A frame index offset relative to the origin parameter.</param>\r\n        /// <param name=\"origin\">A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position.</param>\r\n        /// <returns>The new position within the current stream.</returns>\r\n        /// <exception cref=\"NotSupportedException\">Seek operation is not supported by the current stream.</exception>\r\n        public virtual long Seek(long offset, System.IO.SeekOrigin origin = SeekOrigin.Current)\r\n        {\r\n            if (!this.CanSeek)\r\n                throw new NotSupportedException(\"Seek operation is not supported by the current stream.\");\r\n\r\n            long newPosition = 0;\r\n            switch (origin)\r\n            {\r\n                case SeekOrigin.Begin:\r\n                    newPosition = offset;\r\n                    break;\r\n                case SeekOrigin.Current:\r\n                    newPosition = this.Position + offset;\r\n                    break;\r\n                case SeekOrigin.End:\r\n                    newPosition = this.Length + offset;\r\n                    break;\r\n            }\r\n\r\n            var currentFrame = System.Math.Min(this.Length - 1, System.Math.Max(0, newPosition));\r\n            return currentFrame;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Closes the stream and releases all resources.\r\n        /// <para>Use Dispose function rather than Close function.</para>\r\n        /// </summary>\r\n        public virtual void Dispose()\r\n        {\r\n            this.Close();\r\n        }\r\n\r\n        /// <summary>\r\n        /// When overridden in a derived class, opens the current stream. \r\n        /// </summary>\r\n        public abstract void Open();\r\n\r\n        /// <summary>\r\n        /// When overridden in a derived class, closes the current stream and releases any resources associated with the current stream.\r\n        /// This function is internally called by <see cref=\"Dispose\"/>.\r\n        /// </summary>\r\n        public abstract void Close();\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Base/Abstract/ImageStreamReader.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Threading.Tasks;\r\nusing System;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Image stream reader abstract class. \r\n    /// See generic class also.\r\n    /// </summary>\r\n    public abstract class ImageStreamReader: ImageStreamReader<IImage>\r\n    { }\r\n\r\n    /// <summary>\r\n    /// Image stream writer abstract class. \r\n    /// It is the base class for classes providing image stream reading.\r\n    /// </summary>\r\n    /// <typeparam name=\"TImage\">Image type.</typeparam>\r\n    public abstract class ImageStreamReader<TImage> : ImageStream<TImage>, IEnumerable<TImage>\r\n    {\r\n        /// <summary>\r\n        /// Initializes a new instance of the image reader class.\r\n        /// </summary>\r\n        protected ImageStreamReader()\r\n        {\r\n            this.ReadTimeout = 100;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets a value, in milliseconds, that determines how long the stream will attempt to read before timing out.\r\n        /// </summary>\r\n        public int ReadTimeout { get; set; }\r\n\r\n        /// <summary>\r\n        /// Creates and starts the task responsible for frame reading.\r\n        /// If this function is called <see cref=\"ReadTimeout\"/> must be handled by a user itself.\r\n        /// <remarks>\r\n        /// By using this function reading from some streams can be accelerated.\r\n        /// </remarks>\r\n        /// </summary>\r\n        /// <returns>A image reading task.</returns>\r\n        public Task<TImage> ReadAsync()\r\n        {\r\n            var readTask = new Task<TImage>(() =>\r\n            {\r\n                TImage result;\r\n                ReadInternal(out result);\r\n                return result;\r\n            });\r\n\r\n            readTask.Start();\r\n            return readTask;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Reads an image from the current stream \r\n        /// and advances the position within the stream by 1 element.\r\n        /// </summary>\r\n        /// <param name=\"isExpired\">If a null is returned this can be due to <see cref=\"ReadTimeout\"/> has been reached.</param>\r\n        /// <returns>Read image.</returns>\r\n        public TImage Read(out bool isExpired)\r\n        {\r\n            var readTask = ReadAsync();\r\n            readTask.Wait(this.ReadTimeout);\r\n\r\n            isExpired = !readTask.IsCompleted;\r\n            return readTask.Result;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Reads an image from the current stream \r\n        /// and advances the position within the stream by usually 1 element.\r\n        /// </summary>\r\n        /// <returns>Read image.</returns>\r\n        public TImage Read() \r\n        {\r\n            bool isExpired;\r\n            return Read(out isExpired);\r\n        }\r\n\r\n        /// <summary>\r\n        /// When overridden in a derived class returns an image and a status.\r\n        /// Position is advanced.\r\n        /// </summary>\r\n        /// <param name=\"image\">Read image.</param>\r\n        /// <returns></returns>\r\n        protected abstract bool ReadInternal(out TImage image);\r\n\r\n        #region IEnumerable\r\n\r\n        /// <summary>\r\n        /// Gets the enumerator for the stream.\r\n        /// <para>If the stream does not support seek, an exception will be thrown during iteration.</para>\r\n        /// </summary>\r\n        /// <returns>Enumerator for the stream.</returns>\r\n        public IEnumerator<TImage> GetEnumerator()\r\n        {\r\n            return new ImageStreamReaderEnumerator<TImage>(this);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the enumerator for the stream.\r\n        /// <para>If the stream does not support seek, an exception will be thrown during iteration.</para>\r\n        /// </summary>\r\n        /// <returns>Enumerator for the stream.</returns>\r\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\r\n        {\r\n            return (IEnumerator)GetEnumerator();\r\n        }\r\n\r\n        #endregion\r\n    }\r\n\r\n    /// <summary>\r\n    /// Enumerator for the image stream.\r\n    /// <para>Stream must support seek operation.</para>\r\n    /// </summary>\r\n    /// <typeparam name=\"TImage\">Image type.</typeparam>\r\n    public class ImageStreamReaderEnumerator<TImage> : IEnumerator<TImage>\r\n    {\r\n        ImageStreamReader<TImage> streamableSource;\r\n        long length = -1;\r\n        int position;\r\n\r\n        /// <summary>\r\n        /// Creates new image stream iterator.\r\n        /// </summary>\r\n        /// <param name=\"streamableSource\">Image stream.</param>\r\n        public ImageStreamReaderEnumerator(ImageStreamReader<TImage> streamableSource)\r\n        {\r\n            this.streamableSource = streamableSource;\r\n            this.length = streamableSource.Length;\r\n\r\n            Reset();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Moves the position of the iterator by 1.\r\n        /// </summary>\r\n        /// <returns>True if the position increment is valid, false otherwise.</returns>\r\n        public bool MoveNext()\r\n        {\r\n            position++;\r\n            return position < length;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Resets the enumerator,\r\n        /// </summary>\r\n        public void Reset()\r\n        {\r\n            streamableSource.Seek(0, SeekOrigin.Begin);\r\n            position = -1;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the current image within the stream.\r\n        /// </summary>\r\n        public TImage Current\r\n        {\r\n            get \r\n            {\r\n                var realPos = streamableSource.Position;\r\n\r\n                if (position != realPos)\r\n                    streamableSource.Seek(position, SeekOrigin.Begin);\r\n\r\n                var currentImage = streamableSource.Read();\r\n                return currentImage;\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the current image within the stream.\r\n        /// </summary>\r\n        object System.Collections.IEnumerator.Current\r\n        {\r\n            get { return this.Current; }\r\n        }\r\n\r\n        bool isDisposed = false;\r\n        /// <summary>\r\n        /// Disposes the iterator and resets the position within the stream.\r\n        /// </summary>\r\n        public void Dispose()\r\n        {\r\n            if (!isDisposed)\r\n            {\r\n                Reset();\r\n                isDisposed = true;\r\n            }\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// Provides extensions for image stream.\r\n    /// </summary>\r\n    public static class ImageStreamReaderExtensions\r\n    {\r\n        /// <summary>\r\n        /// Calls read function defined by the stream and converts an returned image if necessary.\r\n        /// <para>If the image can not be read (null), null is returned.</para>\r\n        /// </summary>\r\n        /// <param name=\"imageStream\">Image stream.</param>\r\n        /// <returns>Converted image or null if the image can not be read.</returns>\r\n        public static Image<TColor> ReadAs<TColor>(this ImageStreamReader<IImage> imageStream)\r\n            where TColor: unmanaged\r\n        {\r\n            var image = imageStream.Read();\r\n            if (image == null)\r\n                return null;\r\n\r\n            return image as Image<TColor>;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Reads an element form the input stream and fills the specified buffer.\r\n        /// <para>If the read element does not match the specified type a null value will be written.</para>\r\n        /// </summary>\r\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\r\n        /// <param name=\"imageStream\">Image source stream.</param>\r\n        /// <param name=\"buffer\">\r\n        /// Buffer to write to.\r\n        /// <para>The specified buffer can be null, as it is managed by the function itself.</para>\r\n        /// </param>\r\n        public static void ReadTo<TColor>(this ImageStreamReader<IImage> imageStream, ref TColor[,] buffer)\r\n            where TColor: unmanaged\r\n        { \r\n            imageStream.ReadAs<TColor>().CopyToOrCreate(ref buffer);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Base/Abstract/ImageStreamWriter.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System.Threading.Tasks;\r\nusing System;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Image stream writer abstract class. \r\n    /// See generic class also.\r\n    /// </summary>\r\n    public abstract class ImageStreamWriter : ImageStreamWriter<IImage>\r\n    { }\r\n\r\n    /// <summary>\r\n    /// Image stream writer abstract class. \r\n    /// It is the base class for classes providing image stream reading.\r\n    /// </summary>\r\n    /// <typeparam name=\"TImage\">Image type.</typeparam>\r\n    public abstract class ImageStreamWriter<TImage> : ImageStream<TImage>\r\n    {\r\n        /// <summary>\r\n        /// Initializes a new instance of the image stream writer class.\r\n        /// </summary>\r\n        protected ImageStreamWriter()\r\n        {\r\n            this.WriteTimeout = 500;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets a value, in milliseconds, that determines how long the writer will attempt to write before timing out.\r\n        /// </summary>\r\n        public int WriteTimeout { get; set; }\r\n\r\n        /// <summary>\r\n        /// Creates and starts the task responsible for frame writing.\r\n        /// If this function is called <see cref=\"WriteTimeout\"/> must be handled by a user itself.\r\n        /// <remarks>\r\n        /// By using this function writing to some streams can be accelerated.\r\n        /// </remarks>\r\n        /// </summary>\r\n        /// <returns>An image writing task.</returns>\r\n        public Task<bool> WriteAsync(TImage image)\r\n        {\r\n            var writeTask = new Task<bool>(() =>\r\n            {\r\n                bool success = WriteInternal(image);\r\n                return success;\r\n            });\r\n\r\n            writeTask.Start();\r\n            return writeTask;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Writes an image from the current stream \r\n        /// and advances the position within the stream by 1 element.\r\n        /// </summary>\r\n        /// <returns>\r\n        /// True if the operation is successfully completed, \r\n        /// false if the writer failed to write or the <see cref=\"WriteTimeout\"/> has been reached.\r\n        /// </returns>\r\n        public bool Write(TImage image)\r\n        {\r\n            var writeTask = WriteAsync(image);\r\n            writeTask.Wait(this.WriteTimeout);\r\n\r\n            return writeTask.IsCompleted && writeTask.Result;\r\n        }\r\n\r\n        /// <summary>\r\n        /// When overridden in a derived class returns an image and a status.\r\n        /// Position is advanced.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to write.</param>\r\n        /// <returns>True if successful, false otherwise.</returns>\r\n        protected abstract bool WriteInternal(TImage image);\r\n    }\r\n\r\n    /// <summary>\r\n    /// Provides extensions for an image stream writer.\r\n    /// </summary>\r\n    public static class ImageStreamWriterExtensions\r\n    {\r\n        /// <summary>\r\n        /// Writes a single image into the specified stream.\r\n        /// </summary>\r\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\r\n        /// <param name=\"writer\">image stream writer.</param>\r\n        /// <param name=\"image\">Image to write.</param>\r\n        /// <returns>True if the writing operation is successful, false otherwise.</returns>\r\n        public static bool Write<TColor>(this ImageStreamWriter<Image<TColor>> writer, TColor[,] image)\r\n            where TColor: unmanaged, IColor\r\n        {\r\n            bool result = false;\r\n            using (var uImg = image.Lock())\r\n            {\r\n                result = writer.Write(uImg);\r\n            }\r\n\r\n            return result;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Base/CvInvoke.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System.Drawing;\r\nusing System;\r\nusing System.Runtime.InteropServices;\r\nusing System.Security;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// OpenCV video codec name.\r\n    /// </summary>\r\n    public class VideoCodec\r\n    {\r\n        /// <summary>\r\n        /// MPEG1 codec name: \"PIM1\".\r\n        /// </summary>\r\n        public static readonly VideoCodec MPEG1 = VideoCodec.FromName('P', 'I', 'M', '1');\r\n        /// <summary>\r\n        /// Motion JPEG codec name: \"MJPG\".\r\n        /// </summary>\r\n        public static readonly VideoCodec MotionJpeg = VideoCodec.FromName('M', 'J', 'P', 'G');\r\n        /// <summary>\r\n        /// Intel YUV codec name: \"IYUV\".\r\n        /// </summary>\r\n        public static readonly VideoCodec IntelYUV = VideoCodec.FromName('I', 'Y', 'U', 'V');\r\n        /// <summary>\r\n        /// User selection - on Windows dialog will be opened. Value: -1.\r\n        /// </summary>\r\n        public static readonly VideoCodec UserSelection = new VideoCodec(-1);\r\n\r\n        private const int CODEC_NAME_LENGTH = 4;\r\n        int codec;\r\n\r\n        /// <summary>\r\n        /// Creates new video codec from an id.\r\n        /// </summary>\r\n        /// <param name=\"codec\">Codec id.</param>\r\n        private VideoCodec(int codec)\r\n        {\r\n            this.codec = codec;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Creates new video codec id from 4-character code. For example, FromName('P','I','M','1') is MPEG-1 codec, FromName('M','J','P','G') is motion-jpeg codec etc.\r\n        /// </summary>\r\n        /// <param name=\"c1\">First char.</param>\r\n        /// <param name=\"c2\">Second char.</param>\r\n        /// <param name=\"c3\">Third char.</param>\r\n        /// <param name=\"c4\">Fourth char.</param>\r\n        /// <returns>Video codec.</returns>\r\n        public static VideoCodec FromName(char c1, char c2, char c3, char c4)\r\n        {\r\n            int codec = (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24);\r\n            return new VideoCodec(codec);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Creates new video codec id from 4-character string.\r\n        /// </summary>\r\n        /// <param name=\"codecName\">4-character string codec name.</param>\r\n        /// <returns>Video codec.</returns>\r\n        public static VideoCodec FromName(string codecName)\r\n        {\r\n            if (codecName.Length != CODEC_NAME_LENGTH)\r\n                throw new Exception(\"Codec name is 4-characters long!\");\r\n\r\n            return VideoCodec.FromName(codecName[0], codecName[1], codecName[2], codecName[3]);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Casts video codec to an 32-bit integer.\r\n        /// </summary>\r\n        /// <param name=\"videoCodec\">Video codec.</param>\r\n        /// <returns>32-bit integer representation of the video codec.</returns>\r\n        public static implicit operator int(VideoCodec videoCodec)\r\n        {\r\n            return videoCodec.codec;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Creates video codec from the 32-bit integer.\r\n        /// </summary>\r\n        /// <param name=\"code\">32-bit code.</param>\r\n        /// <returns>New codec name.</returns>\r\n        public static explicit operator VideoCodec(int code)\r\n        {\r\n            return new VideoCodec(code);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Creates video codec from the 4-character string.\r\n        /// </summary>\r\n        /// <param name=\"code\">4-character string.</param>\r\n        /// <returns>New codec name.</returns>\r\n        /// <exception cref=\"System.Exception\">Invalid string length.</exception>\r\n        public static explicit operator VideoCodec(string code)\r\n        {\r\n            return VideoCodec.FromName(code);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the string representation of the codec name.\r\n        /// </summary>\r\n        /// <returns>String representation.</returns>\r\n        public override string ToString()\r\n        {\r\n            unsafe \r\n            {\r\n                fixed (int* intPtr = &this.codec)\r\n                {\r\n                    sbyte* chPtr = (sbyte*)intPtr;\r\n                    return new string(chPtr, 0, CODEC_NAME_LENGTH);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// OpenCV capture properties for camera and video.\r\n    /// </summary>\r\n    internal enum CaptureProperty: int\r\n    {\r\n        PosMsec = 0,\r\n        PosFrames = 1,\r\n        FrameWidth = 3,\r\n        FrameHeight = 4,\r\n        FPS = 5,\r\n        FrameCount = 7,\r\n\r\n        /************** camera properties ******************/\r\n        Brightness = 10,\r\n        Contrast = 11,\r\n        Saturation = 12,\r\n        Hue = 13,\r\n        Gain = 14,\r\n        Exposure = 15,\r\n        /************** camera properties ******************/\r\n\r\n        ConvertRGB = 16\r\n    }\r\n\r\n    /// <summary>\r\n    /// OpenCV image load mode.\r\n    /// </summary>\r\n    [Flags]\r\n    internal enum ImageLoadType : int\r\n    {\r\n        /// <summary>\r\n        /// Loads the image as is (including the alpha channel if present) \r\n        /// </summary>\r\n        Unchanged = -1,\r\n\r\n        /// <summary>\r\n        /// Loads the image as an intensity image\r\n        /// </summary>\r\n        Grayscale = 0,\r\n\r\n        /// <summary>\r\n        ///  Loads the image in the RGB format\r\n        /// </summary>\r\n        Color = 1,\r\n\r\n        /// <summary>\r\n        /// Loads the image of any color\r\n        /// </summary>\r\n        AnyColor = 4,\r\n\r\n        /// <summary>\r\n        /// Loads the image of any depth\r\n        /// </summary>\r\n        AnyDepth = 2\r\n    }\r\n\r\n    /// <summary>\r\n    /// Internal class for OpenCV core / highgui library invocation.\r\n    /// </summary>\r\n    internal static class CvInvoke\r\n    {\r\n        public const CallingConvention CvCallingConvention = CallingConvention.Cdecl;\r\n        public const string OPENCV_CORE_LIBRARY = \"opencv_core2412\";\r\n        public const string OPENCV_HIGHGUI_LIBRARY = \"opencv_highgui2412\";\r\n\r\n        #region Core\r\n\r\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public unsafe static extern void cvReleaseMat(ref CvMat* mat);\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public unsafe static extern void cvReleaseImage(ref IplImage* image);\r\n        #endregion\r\n\r\n        #region Video reader\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern IntPtr cvCreateCameraCapture(int index);\r\n\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern IntPtr cvCreateFileCapture([MarshalAs(UnmanagedType.LPStr)] string filename);\r\n\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern void cvReleaseCapture(ref IntPtr capture);\r\n\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern int cvGrabFrame(IntPtr capture);\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern IntPtr cvQueryFrame(IntPtr capture);\r\n\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern double cvGetCaptureProperty(IntPtr capture, CaptureProperty propertyId);\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        [return: MarshalAs(UnmanagedType.Bool)]\r\n        public static extern bool cvSetCaptureProperty(IntPtr capture, CaptureProperty propertyId, double value);\r\n\r\n        public static Size GetImageSize(IntPtr capturePtr)\r\n        {\r\n            return new Size\r\n            {\r\n                Width = (int)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FrameWidth),\r\n                Height = (int)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FrameHeight)\r\n            };\r\n        }\r\n\r\n        public static bool SetImageSize(IntPtr capturePtr, Size newSize)\r\n        {\r\n            bool success;\r\n            success = CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.FrameWidth, newSize.Width);\r\n            success &= CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.FrameHeight, newSize.Height);\r\n\r\n            return success;\r\n        }\r\n\r\n        #endregion\r\n\r\n        #region Video writer\r\n\r\n        /// <summary>\r\n        /// Creates video writer structure.\r\n        /// </summary>\r\n        /// <param name=\"filename\">Name of the output video file.</param>\r\n        /// <param name=\"fourcc\">4-character code of codec used to compress the frames. See <see cref=\"VideoCodec\"/> class.</param>\r\n        /// <param name=\"fps\">Frame rate of the created video stream. </param>\r\n        /// <param name=\"frameSize\">Size of video frames.</param>\r\n        /// <param name=\"isColor\">If true, the encoder will expect and encode color frames, otherwise it will work with grayscale frames </param>\r\n        /// <returns>The video writer</returns>\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern IntPtr cvCreateVideoWriter([MarshalAs(UnmanagedType.LPStr)] String filename, int fourcc, double fps, Size frameSize, [MarshalAs(UnmanagedType.Bool)] bool isColor);\r\n\r\n        /// <summary>\r\n        /// Writes/appends one frame to video file.\r\n        /// </summary>\r\n        /// <param name=\"writer\">video writer structure.</param>\r\n        /// <param name=\"image\">the written frame</param>\r\n        /// <returns>True on success, false otherwise</returns>\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        [return: MarshalAs(UnmanagedType.Bool)]\r\n        public static extern bool cvWriteFrame(IntPtr writer, IntPtr image);\r\n\r\n        /// <summary>\r\n        /// Finishes writing to video file and releases the structure.\r\n        /// </summary>\r\n        /// <param name=\"writer\">pointer to video file writer structure</param>\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public static extern void cvReleaseVideoWriter(ref IntPtr writer);\r\n        #endregion\r\n\r\n        #region Image IO\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public unsafe static extern IplImage* cvLoadImage([MarshalAs(UnmanagedType.LPStr)] String filename, ImageLoadType loadType);\r\n\r\n        //[SuppressUnmanagedCodeSecurity]\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public unsafe static extern bool cvSaveImage([MarshalAs(UnmanagedType.LPStr)] String filename, IplImage* image, IntPtr parameters);\r\n\r\n        public const int CV_IMWRITE_JPEG_QUALITY = 1;\r\n        public const int CV_IMWRITE_PNG_COMPRESSION = 16;\r\n        public const int CV_IMWRITE_PXM_BINARY = 32;\r\n\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public unsafe static extern CvMat* cvEncodeImage([MarshalAs(UnmanagedType.LPStr)] string ext, CvMat* image, int* parameters = null);\r\n\r\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\r\n        public unsafe static extern CvMat* cvDecodeImageM(void* buffer, ImageLoadType loadType);\r\n\r\n        #endregion Image IO\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/IO.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <Platforms>x64</Platforms>\n    <AssemblyName>DotImaging.IO</AssemblyName>\n    <RootNamespace>DotImaging</RootNamespace>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n    \n  <ItemGroup>\n    <ProjectReference Include=\"..\\Image\\Image.csproj\" />\n  </ItemGroup>\n    \n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <DocumentationFile>bin\\DotImaging.IO.xml</DocumentationFile>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n  </PropertyGroup>\n  \n  <!-- NuGet --> \n  <PropertyGroup>\n    <Version>5.3.0</Version>\n    \n    <PackageId>DotImaging.IO</PackageId>\n    <Description>Loading and saving images and image streams (file, in-memory, camera, video, directory).</Description>\n    <PackageTags>image-encode, image-decode, image-load, image-save, image-directory, camera-capture, multiple-camera-capture, video-capture, video-write</PackageTags>\n\n    <Authors>Darko Jurić</Authors>\n    <Copyright>Darko Jurić</Copyright>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt</PackageLicenseUrl>\n    <PackageIconUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png</PackageIconUrl>\n    <PackageProjectUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</PackageProjectUrl>\n    <RepositoryUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</RepositoryUrl>\n\n    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    <PackageOutputPath>../../Deploy/NuGet/bin/</PackageOutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Folder Include=\"runtimes\\win10-x64\\\" />\n    <Folder Include=\"runtimes\\ubuntu.16.04-x64\\\" />\n\n    <Content Include=\".nuSpec/readmeIO.txt\">\n      <PackagePath>Readme.txt</PackagePath>\n    </Content>\n\n    <!-- Windows -->\n    <Content Include=\"runtimes\\win10-x64\\*.dll\">\n      <Link>runtimes\\win10-x64\\%(FileName)%(Extension)</Link>\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n      <PackagePath>runtimes/win10-x64/native/</PackagePath>\n    </Content>\n\n    <!-- Linux -->\n    <Content Include=\"runtimes\\ubuntu.16.04-x64\\*.so*\">\n      <Link>runtimes\\ubuntu.16.04-x64\\%(FileName)%(Extension)</Link>\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n      <PackagePath>runtimes/ubuntu.16.04-x64/native/</PackagePath>\n    </Content>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/IO/ImageIO.cs",
    "content": "﻿#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Provides methods for image saving and loading\r\n    /// </summary>\r\n    public static class ImageIO \r\n    {\r\n        #region Load (file)\r\n\r\n        private unsafe static IImage load(string fileName, ImageLoadType imageLoadType)\r\n        {\r\n            var iplImagePtr = CvInvoke.cvLoadImage(fileName, imageLoadType);\r\n            var image = (*iplImagePtr).AsImage((_) =>\r\n            {\r\n                if (iplImagePtr == null) return;\r\n                CvInvoke.cvReleaseImage(ref iplImagePtr);\r\n            });\r\n\r\n            return image;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Loads an image with the specified path and name as it is.\r\n        /// </summary>\r\n        /// <param name=\"fileName\">Image file name.</param>\r\n        /// <returns>Image.</returns>\r\n        public unsafe static IImage LoadUnchanged(this string fileName)\r\n        {\r\n            return load(fileName, ImageLoadType.Unchanged);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Loads an image with the specified path and name and performs and RGB conversion.\r\n        /// </summary>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        /// <returns>Image.</returns>\r\n        public unsafe static Bgr<byte>[,] LoadColor(this string fileName)\r\n        {\r\n            Bgr<byte>[,] im = null;\r\n            using (var uIm = load(fileName, ImageLoadType.Color) as Image<Bgr<byte>>)\r\n                im = uIm.Clone();\r\n\r\n            return im;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Loads an image with the specified path and name and performs and gray conversion.\r\n        /// </summary>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        /// <returns>Image.</returns>\r\n        public unsafe static Gray<byte>[,] LoadGray(this string fileName)\r\n        {\r\n            Gray<byte>[,] im = null;\r\n            using (var uIm = load(fileName, ImageLoadType.Grayscale) as Image<Gray<byte>>)\r\n                im = uIm.Clone();\r\n\r\n            return im;\r\n        }\r\n\r\n        #endregion\r\n\r\n        #region Save (file)\r\n\r\n        /// <summary>\r\n        /// Saves the provided image. If the image has non-supported color or depth false value is returned.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Filename.</param>\r\n        /// <returns>True if the image is saved, false otherwise.</returns>\r\n        public unsafe static bool TrySave(IImage image, string fileName)\r\n        {\r\n            IplImage iplImage = default(IplImage);\r\n            try\r\n            {\r\n                iplImage = image.AsCvIplImage();\r\n            }\r\n            catch \r\n            {\r\n                return false;\r\n            }\r\n\r\n            CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero);\r\n            return true;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <typeparam name=\"TColor\">Image color.</typeparam>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        private unsafe static void Save<TColor>(this Image<TColor> image, string fileName)\r\n            where TColor : unmanaged, IColor\r\n        {\r\n            var iplImage = image.AsCvIplImage();\r\n            CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <typeparam name=\"TColor\">Image color.</typeparam>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        private unsafe static void Save<TColor>(this TColor[,] image, string fileName)\r\n            where TColor: unmanaged, IColor\r\n        {\r\n            using (var img = image.Lock())\r\n            {\r\n                var iplImage = img.AsCvIplImage();\r\n                CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero);\r\n            }\r\n        }\r\n\r\n        #region Save-gray\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Gray<byte>[,] image, string fileName)\r\n        {\r\n            image.Save<Gray<byte>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Gray<sbyte>[,] image, string fileName)\r\n        {\r\n            image.Save<Gray<sbyte>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Gray<short>[,] image, string fileName)\r\n        {\r\n            image.Save<Gray<short>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Gray<ushort>[,] image, string fileName)\r\n        {\r\n            image.Save<Gray<ushort>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Gray<int>[,] image, string fileName)\r\n        {\r\n            image.Save<Gray<int>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Gray<float>[,] image, string fileName)\r\n        {\r\n            image.Save<Gray<float>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Gray<double>[,] image, string fileName)\r\n        {\r\n            image.Save<Gray<double>>(fileName);\r\n        }\r\n\r\n        #endregion\r\n\r\n        #region Save-bgr\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgr<byte>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgr<byte>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgr<sbyte>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgr<sbyte>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgr<short>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgr<short>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgr<ushort>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgr<ushort>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgr<int>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgr<int>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgr<float>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgr<float>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgr<double>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgr<double>>(fileName);\r\n        }\r\n\r\n        #endregion\r\n\r\n        #region Save-bgra\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgra<byte>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgra<byte>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgra<sbyte>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgra<sbyte>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgra<short>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgra<short>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgra<ushort>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgra<ushort>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgra<int>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgra<int>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgra<float>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgra<float>>(fileName);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves the specified image.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to save.</param>\r\n        /// <param name=\"fileName\">Image filename.</param>\r\n        public static void Save(this Bgra<double>[,] image, string fileName)\r\n        {\r\n            image.Save<Bgra<double>>(fileName);\r\n        }\r\n\r\n        #endregion\r\n\r\n        #endregion\r\n\r\n        #region Encode\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the Jpeg byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"jpegQuality\">Jpeg quality [0..100] where 100 is the highest quality.</param>\r\n        /// <returns>Jpeg byte array.</returns>\r\n        public static byte[] EncodeAsJpeg(this Gray<byte>[,] image, int jpegQuality = 95)\r\n        {\r\n            return encodeAsJpeg(image, jpegQuality);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the Jpeg byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"jpegQuality\">Jpeg quality [0..100] where 100 is the highest quality.</param>\r\n        /// <returns>Jpeg byte array.</returns>\r\n        public static byte[] EncodeAsJpeg(this Bgr<byte>[,] image, int jpegQuality = 95)\r\n        {\r\n            return encodeAsJpeg(image, jpegQuality);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the Jpeg byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"jpegQuality\">Jpeg quality [0..100] where 100 is the highest quality.</param>\r\n        /// <returns>Jpeg byte array.</returns>\r\n        public static byte[] EncodeAsJpeg(this Gray<ushort>[,] image, int jpegQuality = 95)\r\n        {\r\n            return encodeAsJpeg(image, jpegQuality);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the Jpeg byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"jpegQuality\">Jpeg quality [0..100] where 100 is the highest quality.</param>\r\n        /// <returns>Jpeg byte array.</returns>\r\n        public static byte[] EncodeAsJpeg(this Bgr<ushort>[,] image, int jpegQuality = 95)\r\n        {\r\n            return encodeAsJpeg(image, jpegQuality);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the PNG byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"pngCompression\">PNG compression level [0..9] where 9 is the highest compression.</param>\r\n        /// <returns>PNG byte array.</returns>\r\n        public static byte[] EncodeAsPng(this Gray<byte>[,] image, int pngCompression = 3)\r\n        {\r\n            return encodeAsPng(image, pngCompression);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the PNG byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"pngCompression\">PNG compression level [0..9] where 9 is the highest compression.</param>\r\n        /// <returns>PNG byte array.</returns>\r\n        public static byte[] EncodeAsPng(this Bgr<byte>[,] image, int pngCompression = 3)\r\n        {\r\n            return encodeAsPng(image, pngCompression);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the PNG byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"pngCompression\">PNG compression level [0..9] where 9 is the highest compression.</param>\r\n        /// <returns>PNG byte array.</returns>\r\n        public static byte[] EncodeAsPng(this Bgra<byte>[,] image, int pngCompression = 3)\r\n        {\r\n            return encodeAsPng(image, pngCompression);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the PNG byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"pngCompression\">PNG compression level [0..9] where 9 is the highest compression.</param>\r\n        /// <returns>PNG byte array.</returns>\r\n        public static byte[] EncodeAsPng(this Gray<ushort>[,] image, int pngCompression = 3)\r\n        {\r\n            return encodeAsPng(image, pngCompression);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the PNG byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"pngCompression\">PNG compression level [0..9] where 9 is the highest compression.</param>\r\n        /// <returns>PNG byte array.</returns>\r\n        public static byte[] EncodeAsPng(this Bgr<ushort>[,] image, int pngCompression = 3)\r\n        {\r\n            return encodeAsPng(image, pngCompression);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the PNG byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"pngCompression\">PNG compression level [0..9] where 9 is the highest compression.</param>\r\n        /// <returns>PNG byte array.</returns>\r\n        public static byte[] EncodeAsPng(this Bgra<ushort>[,] image, int pngCompression = 3)\r\n        {\r\n            return encodeAsPng(image, pngCompression);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the specified image type byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"extension\">Image type extension (.bmp, .png, .jpg)</param>\r\n        /// <returns>Image type byte array.</returns>\r\n        public static byte[] Encode(this Gray<byte>[,] image, string extension)\r\n        {\r\n            return encode(image, extension, null);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the specified image type byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"extension\">Image type extension (.bmp, .png, .jpg)</param>\r\n        /// <returns>Image type byte array.</returns>\r\n        public static byte[] Encode(this Bgr<byte>[,] image, string extension)\r\n        {\r\n            return encode(image, extension, null);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the specified image type byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"extension\">Image type extension (.bmp, .png, .jpg)</param>\r\n        /// <returns>Image type byte array.</returns>\r\n        public static byte[] Encode(this Bgra<byte>[,] image, string extension)\r\n        {\r\n            return encode(image, extension, null);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the specified image type byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"extension\">Image type extension (.bmp, .png, .jpg)</param>\r\n        /// <returns>Image type byte array.</returns>\r\n        public static byte[] Encode(this Gray<ushort>[,] image, string extension)\r\n        {\r\n            return encode(image, extension, null);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the specified image type byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"extension\">Image type extension (.bmp, .png, .jpg)</param>\r\n        /// <returns>Image type byte array.</returns>\r\n        public static byte[] Encode(this Bgr<ushort>[,] image, string extension)\r\n        {\r\n            return encode(image, extension, null);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Encodes the specified image into the specified image type byte array.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to encode.</param>\r\n        /// <param name=\"extension\">Image type extension (.bmp, .png, .jpg)</param>\r\n        /// <returns>Image type byte array.</returns>\r\n        public static byte[] Encode(this Bgra<ushort>[,] image, string extension)\r\n        {\r\n            return encode(image, extension, null);\r\n        }\r\n\r\n        static byte[] encodeAsJpeg<TColor>(TColor[,] image, int jpegQuality = 95)\r\n            where TColor : unmanaged, IColor\r\n        {\r\n            if (jpegQuality < 0 || jpegQuality > 100)\r\n                throw new ArgumentOutOfRangeException(\"Jpeg quality must be in range: 0-100.\");\r\n\r\n            int[] parameters = new int[] { CvInvoke.CV_IMWRITE_JPEG_QUALITY, jpegQuality, 0 };\r\n            return encode(image, \".jpg\", parameters);\r\n        }\r\n\r\n        static byte[] encodeAsPng<TColor>(TColor[,] image, int pngCompression = 3)\r\n            where TColor : unmanaged, IColor\r\n        {\r\n            if (pngCompression < 0 || pngCompression > 9)\r\n                throw new ArgumentOutOfRangeException(\"Png compression must be in range: 0-9.\");\r\n\r\n            int[] parameters = new int[] { CvInvoke.CV_IMWRITE_PNG_COMPRESSION, pngCompression, 0 };\r\n            return encode(image, \".png\", parameters);\r\n        }\r\n\r\n        static unsafe byte[] encode<TColor>(TColor[,] image, string extension, int[] parameters)\r\n           where TColor : unmanaged, IColor\r\n        {\r\n            CvMat* matEncoded; //a single-row image\r\n\r\n            using (var uImg = image.Lock())\r\n            {\r\n                fixed (int* paramsPtr = parameters)\r\n                {\r\n                    var mat = uImg.AsCvMat();\r\n                    matEncoded = CvInvoke.cvEncodeImage(extension, &mat, paramsPtr);\r\n                }\r\n            }\r\n\r\n            byte[] imEncoded = new byte[matEncoded->Step * matEncoded->Height];\r\n            fixed (byte* arrPtr = &imEncoded[0])\r\n            {\r\n                Copy.UnsafeCopy(matEncoded->ImageData, (IntPtr)arrPtr, imEncoded.Length);\r\n            }\r\n\r\n            CvInvoke.cvReleaseMat(ref matEncoded); //TODOD: check if this deferences the image\r\n            return imEncoded;\r\n        }\r\n\r\n        #endregion\r\n\r\n        #region Decode\r\n\r\n        /// <summary>\r\n        /// Decodes (and converts if necessary) an image as color image using the specified byte array.\r\n        /// </summary>\r\n        /// <param name=\"encodedImage\">Encoded image.</param>\r\n        /// <returns>Decoded image.</returns>\r\n        public unsafe static Bgr<byte>[,] DecodeAsColorImage(this byte[] encodedImage)\r\n        {\r\n            return decodeImage<Bgr<byte>>(encodedImage, ImageLoadType.Color);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Decodes (and converts if necessary) an image as gray image using the specified byte array.\r\n        /// </summary>\r\n        /// <param name=\"encodedImage\">Encoded image.</param>\r\n        /// <returns>Decoded image.</returns>\r\n        public unsafe static Gray<byte>[,] DecodeAsGrayImage(this byte[] encodedImage)\r\n        {\r\n            return decodeImage<Gray<byte>>(encodedImage, ImageLoadType.Grayscale);\r\n        }\r\n\r\n        unsafe static TColor[,] decodeImage<TColor>(byte[] encodedImage, ImageLoadType loadType)\r\n            where TColor : unmanaged, IColor\r\n        {\r\n            CvMat* matDecoded;\r\n            fixed (byte* encodedImPtr = encodedImage)\r\n            {\r\n                CvMat mat = CvMat.FromUserData((IntPtr)encodedImPtr, encodedImage.Length, 1, encodedImage.Length, CvMat.CvChannelDepth.CV_8U, 1);\r\n                matDecoded = CvInvoke.cvDecodeImageM(&mat, ImageLoadType.Color);\r\n            }\r\n\r\n            var imDecoded = (*matDecoded).ToArray<TColor>();\r\n            CvInvoke.cvReleaseMat(ref matDecoded);\r\n\r\n            return imDecoded;\r\n        }\r\n\r\n        #endregion\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Readers/CameraCapture.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\nusing System.Drawing;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Represents camera stream-able source and provides functions and properties to access a device in a stream-able way.\r\n    /// </summary>\r\n    public class CameraCapture: VideoCaptureBase\r\n    {\r\n        int cameraIdx = 0;\r\n\r\n        /// <summary>\r\n        /// Creates capture from camera.\r\n        /// </summary>\r\n        /// <param name=\"cameraIdx\">Camera index.</param>\r\n        public CameraCapture(int cameraIdx = 0)\r\n        {\r\n            this.cameraIdx = cameraIdx;\r\n            this.CanSeek = false;\r\n            this.IsLiveStream = true;\r\n            this.Open(); //to enable property change\r\n        }\r\n\r\n        /// <summary>\r\n        /// Opens the camera stream.\r\n        /// </summary>\r\n        public override void Open()\r\n        {\r\n            if (capturePtr != IntPtr.Zero)\r\n                return;\r\n            \r\n            capturePtr = CvInvoke.cvCreateCameraCapture(cameraIdx);\r\n            if (capturePtr == IntPtr.Zero)\r\n                throw new Exception(\"Cannot open camera stream! It seems that camera device can not be found.\");\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the brightness of the camera.\r\n        /// <para>If the property is not supported by device 0 will be returned.</para>\r\n        /// </summary>\r\n        public double Brightness\r\n        {\r\n            get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Brightness); }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Brightness, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the contrast of the camera.\r\n        /// <para>If the property is not supported by device 0 will be returned.</para>\r\n        /// </summary>\r\n        public double Contrast\r\n        {\r\n            get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Contrast); }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Contrast, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the exposure of the camera.\r\n        /// <para>If the property is not supported by device 0 will be returned.</para>\r\n        /// </summary>\r\n        public double Exposure\r\n        {\r\n            get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Exposure); }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Exposure, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the gain of the camera.\r\n        /// <para>If the property is not supported by device 0 will be returned.</para>\r\n        /// </summary>\r\n        public double Gain\r\n        {\r\n            get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Gain); }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Gain, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the hue of the camera.\r\n        /// <para>If the property is not supported by device 0 will be returned.</para>\r\n        /// </summary>\r\n        public double Hue\r\n        {\r\n            get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Hue); }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Hue, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the saturation of the camera.\r\n        /// <para>If the property is not supported by device 0 will be returned.</para>\r\n        /// </summary>\r\n        public double Saturation\r\n        {\r\n            get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Saturation); }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Saturation, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the frame size of the camera.\r\n        /// </summary>\r\n        public new Size FrameSize\r\n        {\r\n            get { return CvInvoke.GetImageSize(capturePtr); }\r\n            set { CvInvoke.SetImageSize(capturePtr, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets the frame rate of the camera.\r\n        /// <para>If the property is not supported by device 0 will be returned.</para>\r\n        /// </summary>\r\n        public new double FrameRate\r\n        {\r\n            get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FPS); }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.FPS, value); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the available device count.\r\n        /// <para>Warning: the function closes existing streams, so use it before any camera capture object is created.</para>\r\n        /// </summary>\r\n        public static int CameraCount\r\n        {\r\n            get\r\n            {\r\n                int cameraIdx = 0;\r\n                while (true)\r\n                {\r\n                    var capturePtr = CvInvoke.cvCreateCameraCapture(cameraIdx);\r\n                    if (capturePtr != IntPtr.Zero)\r\n                    {\r\n                        CvInvoke.cvReleaseCapture(ref capturePtr);\r\n                        cameraIdx++;\r\n                    }\r\n                    else\r\n                        break;\r\n                }\r\n\r\n                return cameraIdx;\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Readers/FileCapture.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Linq;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Provides functions and properties to access video file in a streamable way.\r\n    /// </summary>\r\n    public class FileCapture: VideoCaptureBase\r\n    {\r\n        private static readonly string[] supportedRemoteFiles = new string[] { \".mp4\", \".webm\" };\r\n        private static readonly string[] supportedLocalFiles = new string[] { \".mp4\", \".avi\", \".divx\", \".webm\", \".wmv\" };\r\n\r\n        string fileName = null;\r\n\r\n        /// <summary>\r\n        /// Creates capture from video file.\r\n        /// </summary>\r\n        /// <param name=\"sourceName\">\r\n        /// Local file, http uri, ftp uri or a named pipe.\r\n        /// <para>In case of named pipe use: String.Format(@\"\\\\.\\pipe\\{0}\", pipeName) where pipeName is the name of the pipe.</para>\r\n        /// </param>\r\n        public FileCapture(string sourceName)\r\n        {\r\n            if (sourceName.Contains(@\"\\\\.\\pipe\\\"))\r\n            {\r\n                this.CanSeek = false;\r\n            }\r\n            else if (Uri.IsWellFormedUriString(sourceName, UriKind.Absolute))\r\n            {\r\n                var fileExt = Path.GetExtension(sourceName);\r\n                if (supportedRemoteFiles.Any(x => x.Equals(fileExt.ToLower())) == false)\r\n                    throw new UriFormatException(String.Format(\"Uri must point to a supported video file ({0}).\", String.Join(\", \", supportedRemoteFiles)));\r\n\r\n                this.CanSeek = true;\r\n            }\r\n            else\r\n            {\r\n                if (!File.Exists(sourceName))\r\n                    throw new FileNotFoundException(String.Format(\"The file {0} can not be found.\", sourceName));\r\n\r\n                var fileExt = Path.GetExtension(sourceName);\r\n                if (supportedLocalFiles.Any(x => x.Equals(fileExt.ToLower())) == false)\r\n                    throw new UriFormatException(String.Format(\"File must be a supported video file ({0}).\", String.Join(\", \", supportedLocalFiles)));\r\n\r\n                this.CanSeek = true;\r\n            }\r\n       \r\n            this.fileName = sourceName;\r\n            this.Open(); //to enable property change\r\n        }\r\n\r\n        /// <summary>\r\n        /// Opens the video file stream.\r\n        /// </summary>\r\n        public override void Open()\r\n        {\r\n            if (capturePtr != IntPtr.Zero)\r\n                return;\r\n\r\n            capturePtr = CvInvoke.cvCreateFileCapture(fileName);\r\n            if (capturePtr == IntPtr.Zero)\r\n                throw new Exception(\"Cannot open FileStream!\");\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the current position in the stream as frame offset.\r\n        /// </summary>\r\n        public override long Position\r\n        {\r\n            get { return (long)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.PosFrames); }\r\n            protected set { }  \r\n        }\r\n\r\n        /// <summary>\r\n        /// Sets the position within the current stream.\r\n        /// <para>Warning: the underlying OpenCV function seeks to nearest key-frame, therefore the seek operation may not be frame-accurate.</para>\r\n        /// </summary>\r\n        /// <param name=\"offset\">A frame index offset relative to the origin parameter.</param>\r\n        /// <param name=\"origin\">A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position.</param>\r\n        /// <returns>The new position within the current stream.</returns>\r\n        public override long Seek(long offset, System.IO.SeekOrigin origin = SeekOrigin.Current)\r\n        { \r\n            var frameIndex = base.Seek(offset, origin);\r\n            CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.PosFrames, frameIndex);\r\n\r\n            return Position;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Readers/ImageDirectoryCapture.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Represents directory stream-able source and provides functions and properties to access data in a stream-able way.\r\n    /// </summary>\r\n    public class ImageDirectoryCapture : ImageStreamReader\r\n    {\r\n        long currentFrame = 0;\r\n\r\n        #region Initialization\r\n\r\n        /// <summary>\r\n        /// Creates an instance of <see cref=\"ImageDirectoryCapture\"/>.\r\n        /// </summary>\r\n        /// <param name=\"dirPath\">The directory path.</param>\r\n        /// <param name=\"searchPattern\">The image search pattern.</param>\r\n        /// <param name=\"useNaturalSorting\">Use natural sorting, otherwise raw image order is used.</param>\r\n        /// <param name=\"recursive\">If true searches the current directory and all subdirectories. Otherwise, only top directory is searched.</param>\r\n        /// <exception cref=\"DirectoryNotFoundException\">Directory can not be found.</exception>\r\n        public ImageDirectoryCapture(string dirPath, string searchPattern, bool useNaturalSorting = true, bool recursive = false)\r\n            : this(dirPath, new string[] { searchPattern }, useNaturalSorting, recursive)\r\n        { }\r\n\r\n         /// <summary>\r\n        /// Creates an instance of <see cref=\"ImageDirectoryCapture\"/>.\r\n        /// </summary>\r\n        /// <param name=\"dirPath\">The directory path.</param>\r\n        /// <param name=\"searchPatterns\">The image search patterns.</param>\r\n        /// <param name=\"useNaturalSorting\">Use natural sorting, otherwise raw image order is used.</param>\r\n        /// <param name=\"recursive\">If true searches the current directory and all subdirectories. Otherwise, only top directory is searched.</param>\r\n        /// <exception cref=\"DirectoryNotFoundException\">Directory can not be found.</exception>\r\n        public ImageDirectoryCapture(string dirPath, string[] searchPatterns, bool useNaturalSorting = true, bool recursive = false)\r\n        {\r\n            FileReadFunction = ImageIO.LoadUnchanged;\r\n\r\n            if (Directory.Exists(dirPath) == false)\r\n                throw new DirectoryNotFoundException(String.Format(\"Dir: {0} cannot be found!\", dirPath));\r\n\r\n            DirectoryInfo directoryInfo = new DirectoryInfo(dirPath); \r\n\r\n            this.IsLiveStream = false;\r\n            this.CanSeek = true;\r\n            this.DirectoryInfo = directoryInfo;\r\n\r\n            var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;\r\n\r\n            if (useNaturalSorting)\r\n            {\r\n                this.FileInfos = directoryInfo.EnumerateFiles(searchPatterns, searchOption)\r\n                                  .OrderBy(f => f.FullName, new NaturalSortComparer()) //in case of problems replace f.FullName with f.Name\r\n                                  .ToArray();\r\n            }\r\n            else\r\n            {\r\n                this.FileInfos = directoryInfo.EnumerateFiles(searchPatterns, searchOption)\r\n                                  .ToArray();\r\n            }\r\n        }\r\n\r\n        #endregion\r\n\r\n        /// <summary>\r\n        /// Open the current stream. This overload does not do anything.\r\n        /// </summary>\r\n        public override void Open() { }\r\n\r\n        /// <summary>\r\n        /// Closes the current stream. This overload resets position to zero.\r\n        /// </summary>\r\n        public override void Close()\r\n        {\r\n            currentFrame = 0;\r\n        }\r\n\r\n        object syncObj = new object();\r\n        /// <summary>\r\n        /// Reads an image from the stream.\r\n        /// </summary>\r\n        /// <param name=\"image\">Read image.</param>\r\n        /// <returns>True if the reading operation was successful, false otherwise.</returns>\r\n        protected override bool ReadInternal(out IImage image)\r\n        {\r\n            lock (syncObj)\r\n            {\r\n                image = default(IImage);\r\n\r\n                if (this.Position >= this.Length)\r\n                    return false;\r\n\r\n                image = FileReadFunction(FileInfos[currentFrame].FullName);\r\n                currentFrame++;\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the total number of files in the specified directory which match the specified search criteria.\r\n        /// </summary>\r\n        public override long Length { get { return FileInfos.Length; } }\r\n\r\n        /// <summary>\r\n        /// Gets the current position within the stream.\r\n        /// </summary>\r\n        public override long Position { get { return currentFrame; } }\r\n\r\n        /// <summary>\r\n        /// Sets the position within the current stream.\r\n        /// </summary>\r\n        /// <param name=\"offset\">A frame index offset relative to the origin parameter.</param>\r\n        /// <param name=\"origin\">A value of type <see cref=\"System.IO.SeekOrigin\"/> indicating the reference point used to obtain the new position.</param>\r\n        /// <returns>The new position within the current stream.</returns>\r\n        public override long Seek(long offset, SeekOrigin origin = SeekOrigin.Current)\r\n        {\r\n            this.currentFrame = base.Seek(offset, origin);\r\n            return Math.Max(0, Math.Min(currentFrame, this.Length));\r\n        }\r\n\r\n\r\n        #region Specific function\r\n\r\n        /// <summary>\r\n        /// Gets the source directory info.\r\n        /// </summary>\r\n        public DirectoryInfo DirectoryInfo\r\n        {\r\n            get;\r\n            private set;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the ordered set of files which compose the current image directory stream.\r\n        /// </summary>\r\n        public FileInfo[] FileInfos\r\n        {\r\n            get;\r\n            private set;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the current image file name.\r\n        /// <para>If the position of the stream is equal to the stream length null is returned.</para>\r\n        /// </summary>\r\n        public string CurrentImageName\r\n        {\r\n            get { return (this.Position < FileInfos.Length) ? FileInfos[this.Position].FullName : null; }\r\n        }\r\n\r\n        Func<string, IImage> fileReadFunction;\r\n        /// <summary>\r\n        /// Gets or sets the file read function.\r\n        /// <para>A default reading function loads image as it is (unchanged).</para>\r\n        /// </summary>\r\n        public Func<string, IImage> FileReadFunction\r\n        {\r\n            get { return fileReadFunction; }\r\n            set\r\n            {\r\n                if (value == null)\r\n                    new ArgumentNullException(\"File read function can not be null.\");\r\n\r\n                fileReadFunction = value;\r\n            }\r\n        }\r\n\r\n        #endregion\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Readers/VideoCaptureBase.cs",
    "content": "#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\nusing System.Drawing;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Represents the base class for video capture that shares common functions and properties with camera and file capture. \r\n    /// </summary>\r\n    public abstract class VideoCaptureBase : ImageStreamReader\r\n    {\r\n        /// <summary>\r\n        /// Internal OpenCV pointer for the capture object.\r\n        /// </summary>\r\n        protected IntPtr capturePtr;\r\n\r\n        /// <summary>\r\n        /// Releases all resources allocated by capture.\r\n        /// </summary>\r\n        public override void Close()\r\n        {\r\n            if (capturePtr != IntPtr.Zero)\r\n                CvInvoke.cvReleaseCapture(ref capturePtr);\r\n        }\r\n\r\n        object syncObj = new object();\r\n        /// <summary>\r\n        /// Reads the next image in the stream and advances the position by one.\r\n        /// </summary>\r\n        /// <param name=\"image\">Read image.</param>\r\n        /// <returns>True if the reading operation was successful, false otherwise.</returns>\r\n        protected override bool ReadInternal(out IImage image)\r\n        {\r\n            bool status = false;\r\n            image = default(IImage);\r\n\r\n            lock (syncObj)\r\n            {\r\n                IntPtr cvFramePtr;\r\n                cvFramePtr = CvInvoke.cvQueryFrame(capturePtr);\r\n\r\n                if (cvFramePtr != IntPtr.Zero)\r\n                {\r\n                    image = IplImage.FromPointer(cvFramePtr).AsImage();\r\n                    this.Position++;\r\n                    status = true;\r\n                }\r\n            }\r\n\r\n            return status;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the length in number of frames.\r\n        /// </summary>\r\n        public override long Length\r\n        {\r\n            get { return (long)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FrameCount); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets or sets whether to force conversion of an input image to Bgr color type.\r\n        /// </summary>\r\n        public bool ConvertRgb\r\n        {\r\n            get { return (int)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.ConvertRGB) != 0; }\r\n            set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.ConvertRGB, value ? 0 : 1); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the frame size.\r\n        /// </summary>\r\n        public Size FrameSize\r\n        {\r\n            get { return CvInvoke.GetImageSize(capturePtr); }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the frame rate.\r\n        /// </summary>\r\n        public float FrameRate\r\n        {\r\n            get { return (float)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FPS); }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Utilities/NaturalSortComparer.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Text.RegularExpressions;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides functions for natural string comparison.\n    /// Reference: <seealso cref=\"https://www.codeproject.com/Articles/22517/Natural-Sort-Comparer\"/>.\n    /// </summary>\n    class NaturalSortComparer: IComparer<string>\n    {\n        private bool isAscending;\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"NaturalSortComparer\"/>.\n        /// </summary>\n        /// <param name=\"inAscendingOrder\">Sorts in ascending order, otherwise descending.</param>\n        public NaturalSortComparer(bool inAscendingOrder = true)\n        {\n            this.isAscending = inAscendingOrder;\n        }\n\n        #region IComparer<string> Members\n\n        /// <summary>\n        /// Compares two strings.\n        /// </summary>\n        /// <param name=\"x\">First string.</param>\n        /// <param name=\"y\">Second string.</param>\n        /// <returns>0 - the same objects, -1, +1 otherwise depending whether the first string precedes the second one or not.</returns>\n        public int Compare(string x, string y)\n        { \n            throw new NotImplementedException();\n        }\n\n        #endregion\n\n        #region IComparer<string> Members\n\n        int IComparer<string>.Compare(string x, string y)\n        {\n            if (x == y)\n                return 0;\n\n            string[] x1, y1;\n\n            if (!table.TryGetValue(x, out x1))\n            {\n                x1 = Regex.Split(x.Replace(\" \", \"\"), \"([0-9]+)\");\n                table.Add(x, x1);\n            }\n\n            if (!table.TryGetValue(y, out y1))\n            {\n                y1 = Regex.Split(y.Replace(\" \", \"\"), \"([0-9]+)\");\n                table.Add(y, y1);\n            }\n\n            int returnVal;\n\n            for (int i = 0; i < x1.Length && i < y1.Length; i++)\n            {\n                if (x1[i] != y1[i])\n                {\n                    returnVal = PartCompare(x1[i], y1[i]);\n                    return isAscending ? returnVal : -returnVal;\n                }\n            }\n\n            if (y1.Length > x1.Length)\n            {\n                returnVal = 1;\n            }\n            else if (x1.Length > y1.Length)\n            {\n                returnVal = -1;\n            }\n            else\n            {\n                returnVal = 0;\n            }\n\n            return isAscending ? returnVal : -returnVal;\n        }\n\n        private static int PartCompare(string left, string right)\n        {\n            int x, y;\n            if (!int.TryParse(left, out x))\n                return left.CompareTo(right);\n\n            if (!int.TryParse(right, out y))\n                return left.CompareTo(right);\n\n            return x.CompareTo(y);\n        }\n\n        #endregion\n\n        private Dictionary<string, string[]> table = new Dictionary<string, string[]>();\n    }\n}\n"
  },
  {
    "path": "Source/IO/Utilities/PathExtensions.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// <para>Defined functions can be used as object extensions.</para>\n    /// Provides methods for string which is treated as file and directory path.\n    /// </summary>\n    static class PathExtensions\n    {\n        /// <summary>\n        /// Returns an enumerable collection of file information that matches a specified search pattern and search subdirectory option.\n        /// </summary>\n        /// <param name=\"dirInfo\">Directory info.</param>\n        /// <param name=\"searchPatterns\">The search strings (e.g. new string[]{ \".jpg\", \".bmp\" }</param>\n        /// <param name=\"searchOption\">\n        /// One of the enumeration values that specifies whether the search operation\n        /// should include only the current directory or all subdirectories. The default\n        /// value is <see cref=\"System.IO.SearchOption.TopDirectoryOnly\"/>.\n        ///</param>\n        /// <returns>An enumerable collection of files that matches <paramref name=\"searchPatterns\"/> and <paramref name=\"searchOption\"/>.</returns>\n        public static IEnumerable<FileInfo> EnumerateFiles(this DirectoryInfo dirInfo, string[] searchPatterns, SearchOption searchOption = SearchOption.TopDirectoryOnly)\n        {\n            var fileInfos = new List<FileInfo>();\n            foreach (var searchPattern in searchPatterns)\n            {\n                var dirFileInfos = dirInfo.EnumerateFiles(searchPattern, searchOption);\n                fileInfos.AddRange(dirFileInfos);\n            }\n\n            return fileInfos;\n        }\n\n    }\n}\n"
  },
  {
    "path": "Source/IO/Writers/ImageWriterExtension.cs",
    "content": "﻿#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\n\r\nnamespace DotImaging\r\n{\r\n\r\n    /// <summary>\r\n    /// Provides extensions for image extraction from image streams.\r\n    /// </summary>\r\n    public static class ImageWriterExtension\r\n    {\r\n        /// <summary>\r\n        /// Reads the image source and save the extracted images to the specified folder.\r\n        /// </summary>\r\n        /// <param name=\"imageSource\">Image stream reader.</param>\r\n        /// <param name=\"outputDir\">Output directory.</param>\r\n        /// <param name=\"fileNameFormat\">Image file name format.</param>\r\n        /// <param name=\"onFrameCompletition\">Progress function executed after a frame is saved.</param>\r\n        public static void SaveFrames(this ImageStreamReader imageSource, string outputDir, \r\n                                      string fileNameFormat = \"img-{0:000}.png\", \r\n                                      Action<float> onFrameCompletition = null)\r\n        {\r\n            if (!Directory.Exists(outputDir))\r\n                Directory.CreateDirectory(outputDir);\r\n\r\n            if (imageSource.CanSeek)\r\n                imageSource.Seek(0, SeekOrigin.Begin);\r\n\r\n            var idx = 0;\r\n            foreach (var frame in imageSource) //use video stream as IEnumerable<IImage> (must support seek operation)\r\n            {\r\n                if (frame != null) //some videos skip key frames (discard those frames)\r\n                {\r\n                    var path = Path.Combine(outputDir, String.Format(fileNameFormat, idx));\r\n                    ImageIO.TrySave(frame, path); //TODO-noncritical: add compression options\r\n                }\r\n\r\n                if(onFrameCompletition != null)\r\n                    onFrameCompletition((float)(idx + 1) / imageSource.Length);\r\n\r\n                idx++;\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Source/IO/Writers/VideoWriter.cs",
    "content": "﻿#region Licence and Terms\r\n// DotImaging Framework\r\n// https://github.com/dajuric/dot-imaging\r\n//\r\n// Copyright © Darko Jurić, 2014-2019\r\n// darko.juric2@gmail.com\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//    http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n//\r\n#endregion\r\n\r\nusing System;\r\nusing System.Drawing;\r\n\r\nnamespace DotImaging\r\n{\r\n    /// <summary>\r\n    /// Video writer that writes images into video file.\r\n    /// </summary>\r\n    public class VideoWriter : ImageStreamWriter\r\n    {\r\n        object syncObj = new object();\r\n        IntPtr videoObjPtr = IntPtr.Zero;\r\n\r\n        /// <summary>\r\n        /// Gets the output file name.\r\n        /// </summary>\r\n        public string OutputFileName { get; private set; }\r\n\r\n        /// <summary>\r\n        /// Gets whether the frame must consist of 3-channels (color) or from just one (grayscale).\r\n        /// </summary>\r\n        public bool ColorFrames { get; private set; }\r\n\r\n        /// <summary>\r\n        /// Gets the codec used to encode frames.\r\n        /// </summary>\r\n        public VideoCodec Codec { get; private set; }\r\n\r\n        /// <summary>\r\n        /// Gets the number of frames per second.\r\n        /// </summary>\r\n        public float FrameRate { get; private set; }\r\n\r\n        /// <summary>\r\n        /// Gets the frame size.\r\n        /// </summary>\r\n        public Size FrameSize { get; private set; }\r\n\r\n        /// <summary>\r\n        /// Creates new video writer (with default codec).\r\n        /// </summary>\r\n        /// <param name=\"fileName\">Video file name.</param>\r\n        /// <param name=\"frameSize\">Video frame size.</param>\r\n        /// <param name=\"fps\">Specifies the number of frames per second.</param>\r\n        /// <param name=\"isColor\">Specifies whether the image is color image (3 channels) or grayscale image (one channel).</param>\r\n        public VideoWriter(string fileName, Size frameSize, float fps = 30, bool isColor = true)\r\n            : this(fileName, frameSize, fps, isColor, VideoCodec.MotionJpeg)\r\n        { }\r\n\r\n        /// <summary>\r\n        /// Creates new video writer.\r\n        /// </summary>\r\n        /// <param name=\"fileName\">Video file name.</param>\r\n        /// <param name=\"frameSize\">Video frame size.</param>\r\n        /// <param name=\"fps\">Specifies the number of frames per second.</param>\r\n        /// <param name=\"isColor\">Specifies whether the image is color image (3 channels) or grayscale image (one channel).</param>\r\n        /// <param name=\"videoCodec\">Specifies used codec for video encoding.</param>\r\n        public VideoWriter(string fileName, Size frameSize, float fps, bool isColor, VideoCodec videoCodec)\r\n        {\r\n            this.CanSeek = false;\r\n            this.IsLiveStream = true;\r\n\r\n            this.OutputFileName = fileName;\r\n            this.ColorFrames = isColor;\r\n            this.Codec = videoCodec;\r\n            this.FrameSize = frameSize;\r\n            this.FrameRate = fps;\r\n\r\n            this.Open(); //to enable property change\r\n        }\r\n\r\n        /// <summary>\r\n        /// Opens the video file stream.\r\n        /// </summary>\r\n        public override void Open()\r\n        {\r\n            if (videoObjPtr != IntPtr.Zero)\r\n                return;\r\n\r\n            videoObjPtr = CvInvoke.cvCreateVideoWriter(OutputFileName, (int)Codec, FrameRate, FrameSize, ColorFrames);\r\n            if (videoObjPtr == IntPtr.Zero)\r\n                throw new Exception(String.Format(\"Cannot open FileStream! Please check that the selected codec ({0}) is supported.\", Codec));\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the current position in the stream as frame offset.\r\n        /// </summary>\r\n        public override long Position\r\n        {\r\n            get;\r\n            protected set;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the current stream length which is not constant and is the same as position.\r\n        /// </summary>\r\n        public override long Length\r\n        {\r\n            get { return this.Position; }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Writes the provided image to the stream.\r\n        /// </summary>\r\n        /// <param name=\"image\">Image to write.</param>\r\n        /// <returns>True, if the operation was successful, false otherwise.</returns>\r\n        protected unsafe override bool WriteInternal(IImage image)\r\n        {\r\n            bool isSuccessful;\r\n\r\n            lock (syncObj)\r\n            {\r\n                if (image.ColorInfo.ChannelCount == 3 && !ColorFrames)\r\n                    throw new Exception(\"Image must be grayscale!\");\r\n\r\n                if (image.ColorInfo.ChannelCount == 1 && ColorFrames)\r\n                    throw new Exception(\"Image must be color!\");\r\n\r\n                if (image.ColorInfo.ChannelCount != 3 && ColorFrames)\r\n                    throw new Exception(\"Color images must have 3 channels!\");\r\n\r\n                if (!image.Size.Equals(FrameSize))\r\n                    throw new Exception(\"Input image must be the same size as defined frame size!\");\r\n\r\n                this.Position++;\r\n\r\n                var iplImg = image.AsCvIplImage();\r\n                IplImage* iplImgPtr = (IplImage*)&iplImg;\r\n\r\n                isSuccessful = CvInvoke.cvWriteFrame(videoObjPtr, (IntPtr)iplImgPtr);\r\n            }\r\n\r\n            return isSuccessful;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Closes video writer.\r\n        /// <para>Use dispose method to remove any additional resources.</para>\r\n        /// </summary>\r\n        public override void Close()\r\n        {\r\n            if (videoObjPtr != IntPtr.Zero)\r\n                CvInvoke.cvReleaseVideoWriter(ref videoObjPtr);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Source/IO.Web/.nuSpec/readmeIO.Web.txt",
    "content": "﻿ Provides support for image or video download/streaming (direct video link or Youtube links).\n\n1) image loading:\n  \n   new Uri(\"http://vignette3.wikia.nocookie.net/disney/images/5/5d/Lena_headey_.jpg\")\n        .GetBytes()\n        .DecodeAsColorImage()\n\t.Show(); //requires UI package\n\n2) video streaming:\n\n    var sourceName = String.Empty;\n\n    var pipeName = new Uri(\"https://www.youtube.com/watch?v=Vpg9yizPP_g\").NamedPipeFromYoutubeUri(); //Youtube\n    sourceName = String.Format(@\"\\\\.\\pipe\\{0}\", pipeName);\n    \n    //sourceName = \"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4\"; //direct http streaming \n\n    //------------------------------------------------------------------\n    ImageStreamReader reader = new FileCapture(sourceName);\n    reader.Open();\n\n    //seek if you can\n    if(reader.CanSeek)\n       reader.Seek((int)(reader.Length * 0.25), System.IO.SeekOrigin.Begin);\n\n    //read video frames\n    Bgr<byte>[,] frame = null;\n    do\n    {\n\treader.ReadTo(ref frame);\n\tif (frame == null)\n\t\tbreak;\n\n\tframe.Show(scaleForm: true);\n\t((double)reader.Position / reader.Length).Progress();\n     }\n     while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape));\n\n\n3) video download:\n\n   string fileExtension;\n   pipeName = new Uri(\"https://www.youtube.com/watch?v=Vpg9yizPP_g\").NamedPipeFromYoutubeUri(out fileExtension); //Youtube\n   pipeName.SaveNamedPipeStream(\"out\" + fileExtension);\n\n\nDiscover more types as you type :)\n"
  },
  {
    "path": "Source/IO.Web/IO.Web.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <AssemblyName>DotImaging.IO.Web</AssemblyName>\n    <RootNamespace>DotImaging</RootNamespace>\n    <Platforms>AnyCPU</Platforms>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"VideoLibrary\" Version=\"2.0.3\" />\n  </ItemGroup>\n\t\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Image\\Image.csproj\" />\n  </ItemGroup> \n\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <DocumentationFile>bin\\DotImaging.IO.Web.xml</DocumentationFile>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n  </PropertyGroup>\n\n  <!-- NuGet -->\n  <PropertyGroup>\n    <Version>5.3.0</Version>\n\n    <PackageId>DotImaging.IO.Web</PackageId>\n    <Description>Image or video download/streaming (direct video link or Youtube links).</Description>\n    <PackageTags>web-image, image-download, video-download, video-streaming, Youtube, web-video</PackageTags>\n\n    <Authors>Darko Jurić</Authors>\n    <Copyright>Darko Jurić</Copyright>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt</PackageLicenseUrl>\n    <PackageIconUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png</PackageIconUrl>\n    <PackageProjectUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</PackageProjectUrl>\n    <RepositoryUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</RepositoryUrl>\n\n    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    <PackageOutputPath>../../Deploy/NuGet/bin/</PackageOutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\".nuSpec/readmeIO.Web.txt\">\n      <PackagePath>Readme.txt</PackagePath>\n    </Content>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/IO.Web/NamedPipeExtensions.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Threading.Tasks;\nusing System.IO.Pipes;\nusing System.Net;\nusing VideoLibrary;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides named pipe creation extension for Uri, string and Stream.\n    /// </summary>\n    public static class NamedPipeExtensions\n    {\n        #region Reading\n\n        /// <summary>\n        /// Creates a new named pipe from a file stream.\n        /// </summary>\n        /// <param name=\"fileName\">File name.</param>\n        /// <param name=\"namedPipeName\">Named pipe.</param>\n        /// <param name=\"onProgress\">Function executed when progress changes. Return true to cancel the operation, false to continue.</param>\n        /// <returns>Pipe name.</returns>\n        public static string NamedPipeFromFileName(this string fileName, string namedPipeName = \"filePipe\", Func<float, bool> onProgress = null)\n        {\n            if (File.Exists(fileName))\n                throw new ArgumentException(\"The provided file does not exist.\", nameof(fileName));\n\n            Stream source = File.OpenRead(fileName);\n\n            return NamedPipeFromStreamAsync(source, namedPipeName, onProgress, () =>\n            {\n                source.Dispose();\n            });\n        }\n\n        /// <summary>\n        /// Creates a new named pipe from a link (video-link if used in conjunction with IO package).\n        /// </summary>\n        /// <param name=\"uri\">Uri to web file.</param>\n        /// <param name=\"namedPipeName\">Named pipe.</param>\n        /// <param name=\"onProgress\">Function executed when progress changes. Return true to cancel the operation, false to continue.</param>\n        /// <returns>Pipe name.</returns>\n        public static string NamedPipeFromVideoUri(this Uri uri, string namedPipeName = \"webPipe\", Func<float, bool> onProgress = null)\n        {\n            var request = (HttpWebRequest)WebRequest.Create(uri.AbsoluteUri);\n            WebResponse response = request.GetResponse();\n            Stream source = response.GetResponseStream();\n\n            return NamedPipeFromStreamAsync(source, namedPipeName, onProgress, () =>\n            {\n                source.Dispose();\n                response.Dispose();\n            });\n        }\n\n        /// <summary>\n        /// Creates a new named pipe from a Youtube video link.\n        /// </summary>\n        /// <param name=\"youtubeUri\">Uri to Youtube video file.</param>\n        /// <param name=\"fileExtension\">Video-file extension.</param>\n        /// <param name=\"namedPipeName\">Named pipe.</param>\n        /// <param name=\"onProgress\">Function executed when progress changes. Return true to cancel the operation, false to continue.</param>\n        /// <returns>Pipe name.</returns>\n        public static string NamedPipeFromYoutubeUri(this Uri youtubeUri, out string fileExtension, string namedPipeName = \"youtubeVideoPipe\", Func<float, bool> onProgress = null)\n        {\n            if (youtubeUri.Host != \"www.youtube.com\")\n                throw new ArgumentException(\"The provided URI is not valid Youtube URI.\");\n\n            var youtubeVideo = YouTube.Default.GetVideo(youtubeUri.AbsoluteUri); \n            fileExtension = youtubeVideo.FileExtension;\n\n            VideoClient vc = new VideoClient();\n            Stream source = vc.Stream(youtubeVideo);\n            \n            return NamedPipeFromStreamAsync(source, namedPipeName, onProgress, () =>\n            {\n                source.Dispose();\n                vc.Dispose();\n            });\n        }\n\n        /// <summary>\n        /// Creates a new named pipe from a Youtube video link.\n        /// </summary>\n        /// <param name=\"youtubeUri\">Uri to Youtube video file.</param>\n        /// <param name=\"namedPipeName\">Named pipe.</param>\n        /// <param name=\"onProgress\">Function executed when progress changes. Return true to cancel the operation, false to continue.</param>\n        /// <returns>Pipe name.</returns>\n        public static string NamedPipeFromYoutubeUri(this Uri youtubeUri, string namedPipeName = \"youtubeVideoPipe\", Func<float, bool> onProgress = null)\n        {\n            string fileExtension;\n            return NamedPipeFromYoutubeUri(youtubeUri, out fileExtension, namedPipeName, onProgress);\n        }\n\n        /// <summary>\n        /// Creates a new named pipe from a Youtube video link.\n        /// </summary>\n        /// <param name=\"source\">Source stream.</param>\n        /// <param name=\"namedPipeName\">Named pipe.</param>\n        /// <param name=\"onProgress\">Function executed when progress changes. Return true to cancel the operation, false to continue.</param>\n        /// <param name=\"onFinish\">Action executed when a reading operation finishes.</param>\n        /// <returns>Pipe name.</returns>\n        public static string NamedPipeFromStreamAsync(this Stream source, string namedPipeName, Func<float, bool> onProgress = null, Action onFinish = null)\n        {\n            if (source == null)\n                new ArgumentNullException(nameof(source));\n\n            Task.Factory.StartNew(() =>\n            {\n                using (NamedPipeServerStream target = new NamedPipeServerStream(namedPipeName))\n                {\n                    target.WaitForConnection();\n                    target.WaitForPipeDrain();\n\n                    int bytes, copiedBytes = 0;\n                    var buffer = new byte[1024];\n                    while ((bytes = source.Read(buffer, 0, buffer.Length)) > 0)\n                    {\n                        target.Write(buffer, 0, bytes);\n                        copiedBytes += bytes;\n\n                        if (onProgress != null)\n                        {\n                            bool shouldCancel = onProgress((float)copiedBytes / source.Length);\n                            if (shouldCancel)\n                                break;\n                        }\n                    }\n\n                    target.Flush();\n                    if (onFinish != null) onFinish();\n                }\n            });\n\n            return namedPipeName;\n        }\n\n        #endregion\n\n        #region Writing\n\n        /// <summary>\n        /// Copies the named pipe stream to the specified stream.\n        /// </summary>\n        /// <param name=\"pipeName\">Pipe name.</param>\n        /// <param name=\"target\">Destination stream.</param>\n        public static void CopyNamedPipeStream(this string pipeName, Stream target)\n        {\n            using (NamedPipeClientStream clientPipe = new NamedPipeClientStream(pipeName))\n            {\n                clientPipe.Connect();\n\n                int bytes, copiedBytes = 0;\n                var buffer = new byte[1024];\n                while ((bytes = clientPipe.Read(buffer, 0, buffer.Length)) > 0)\n                {\n                    target.Write(buffer, 0, bytes);\n                    copiedBytes += bytes;\n\n                    /*if (onProgress != null)\n                    {\n                        bool shouldCancel = onProgress((float)copiedBytes / clientPipe.Length);\n                        if (shouldCancel)\n                            break;\n                    }*/\n                }\n\n                target.Flush();\n            }\n        }\n\n        /// <summary>\n        /// Saves the named pipe stream to the specified file.\n        /// </summary>\n        /// <param name=\"pipeName\">Pipe name.</param>\n        /// <param name=\"targetFile\">Destination file.</param>\n        public static void SaveNamedPipeStream(this string pipeName, string targetFile)\n        {\n            using (Stream target = File.Create(targetFile))\n            {\n                CopyNamedPipeStream(pipeName, target);\n            }\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Source/IO.Web/WebImageExtensions.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Net;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides extensions for getting images from the Web.\n    /// </summary>\n    public static class WebImageExtensions\n    {\n        /// <summary>\n        /// Gets the bytes from the Web using the specified uri.\n        /// </summary>\n        /// <param name=\"uri\">File Web location.</param>\n        /// <param name=\"onProgress\">Function executed when progress changes. Return true to cancel the operation, false to continue.</param>\n        /// <returns>Encoded image or undefined output in case if the operation is canceled.</returns>\n        public static byte[] GetBytes(this Uri uri, Func<float, bool> onProgress = null)\n        {\n            byte[] output = null;\n            var request = (HttpWebRequest)WebRequest.Create(uri.AbsoluteUri);\n\n            using (WebResponse response = request.GetResponse())\n            using (Stream source = response.GetResponseStream())\n            using(MemoryStream target = new MemoryStream())\n            {\n                int bytes, copiedBytes = 0;\n                var buffer = new byte[1024];\n                while ((bytes = source.Read(buffer, 0, buffer.Length)) > 0)\n                {\n                    target.Write(buffer, 0, bytes);\n                    copiedBytes += bytes;\n\n                    if (onProgress != null)\n                    {\n                        bool shouldCancel = onProgress((float)copiedBytes / response.ContentLength);\n                        if (shouldCancel)\n                            break;\n                    }\n                }\n\n                target.Flush();\n                output = target.ToArray();\n            }\n\n            return output;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/.nuSpec/readmeImage.txt",
    "content": "﻿Provides .NET native array imaging extensions. Color-spaces and channel depth conversion is included.\nImplements slim generic image class when fast pixel manipulation is needed.\nTo get compatibility for other image types install appropriate extension - NuGet package (e.g. Imaging.BitmapInterop).\n\n1) Color and depth conversion:\n\n\tBgr<byte>[,] image = ImageIO.LoadColor(\"sample.jpg\"); //requires DotImaging.IO package\n\tGray<float> grayFloatIm = image.ToGray()\n\t                               .Cast<float>();\n\n\n2) Splitting and merging channels:\n\n    Bgra<byte>[,] image = new Bgra<byte>[480, 640];\n\tGray<byte>[][,] channels = image.SplitChannels(0, 1, 2); //take B, G and R channel\n\tBgr<byte> bgrIm = channels.MergeChannels<Bgr<byte>, byte>();\n\n\n3) Unsafe operations:\n\n     Bgr<byte>[,] image = new Bgr<byte>[240, 320];\n\n\t using(var unmanagedImage = image.Lock()) //create unmanaged structure that shares data with the array\n\t {\n\t\tBgr8* ptr = (Bgr8*)unmanagedImage.GetData(10, 10);\n\t\tptr->B = 111;\n\t }\n\n\n4) OpenCV compatibility:\n\n    Gray<byte>[,] image = new Gray<byte>[240, 320];\n\n\tIplImage iplIm = image.AsOpenCvImage(); //to OpenCV image\n\tGray<byte>[,] imFromIpl = iplIm.AsImage().Clone(); //to array\n\n\n5) LINQ:\n\n\tBgr<byte>[,] image = ImageIO.LoadColor(\"sample.jpg\").Clone();\n\n\t//get the modified blue channel \n\tvar modifiedImage = image.AsEnumerable()\n\t                         .Select(x => x.B / 2)\n\t\t\t\t\t\t\t .ToArray2D(image.Size());\n\n\n6) Misc\n\n   Hsv<byte>[,] image = new Hsv<byte>[240, 320];\n   image.SetValue(new Hsv<byte>(10, 10, 255)); //set pixels value\n\n   Console.WriteLine(image.Size()); //write image size\n   Console.WriteLine(image.ColorInfo()); //write color info\n   ...\n\n\nDiscover more extensions as you type :)\n\n"
  },
  {
    "path": "Source/Image/ColorTypeConversions/ColorInfo.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Gets color information from color type and depth type.\n    /// </summary>\n    public class ColorInfo: IEquatable<ColorInfo>\n    {\n        static ConcurrentDictionary<Type, ColorInfo> colorInfos = new ConcurrentDictionary<Type, ColorInfo>();\n\n        /// <summary>\n        /// Color type (IColor).\n        /// </summary>\n        public Type ColorType { get; private set; }\n        /// <summary>\n        /// Number of channels that color has.\n        /// </summary>\n        public int ChannelCount { get; private set; }\n        /// <summary>\n        /// Number of bytes per channel.\n        /// </summary>\n        public int ChannelSize { get; private set; }\n        /// <summary>\n        /// Channel type. Only primitive types are supported.\n        /// </summary>\n        public Type ChannelType { get; private set; }\n        /// <summary>\n        /// Color size in bytes. Number of channels multiplied by channel size.\n        /// </summary>\n        public int Size { get { return this.ChannelSize * this.ChannelCount; } }\n\n        /// <summary>\n        /// Gets color info (depth is taken from color).\n        /// </summary>\n        /// <typeparam name=\"TColor\">Member of <see cref=\"IColor\"/></typeparam>\n        /// <returns>Color info</returns>\n        public static ColorInfo GetInfo<TColor>()\n            //where TColor : IColor<T>\n        {\n            return GetInfo(typeof(TColor));\n        }\n\n        /// <summary>\n        /// Gets color info (depth is taken from color).\n        /// </summary>\n        /// <param name=\"colorType\">Color type. (member of IColor)</param>\n        /// <returns>Color info</returns>\n        public static ColorInfo GetInfo(Type colorType)\n        {\n            return colorInfos.GetOrAdd(colorType, getInfo);\n        }\n\n        private static ColorInfo getInfo(Type colorType)\n        {\n            ColorInfo ci = new ColorInfo();\n            ci.ColorType = colorType;\n\n            Type channelType;  int numberOfChannels;\n            getChannelInfo(colorType, out channelType, out numberOfChannels);\n\n            ci.ChannelCount = numberOfChannels;\n            ci.ChannelType = channelType;\n            ci.ChannelSize = Marshal.SizeOf(channelType);\n\n            return ci;\n        }\n\n        private static void getChannelInfo(Type colorType, out Type channelType, out int numberOfChannels)\n        {\n            numberOfChannels = 0;\n\n            var channelTypes = colorType\n                               .GetFields(BindingFlags.Public | ~BindingFlags.Static) //if BindingFlags.Instance and if colorType is byte => zero length array\n                               .Select(x => x.FieldType)\n                               .ToArray();\n\n            //ensure that all types are the same\n            var _channelType = channelTypes[0];\n            if (channelTypes.Where(x => x.Equals(_channelType)).Count() != channelTypes.Length)\n                throw new Exception(\"Public fields must have the same type!\");\n\n            if (channelTypes.Length == 0)\n                throw new Exception(\"Color structure must have at least one public field!\");\n\n            if (!_channelType.IsValueType)\n                throw new Exception(\"Channel type must be a value type!\");\n\n            if (!_channelType.IsPrimitive)\n                throw new Exception(\"Channel type must be a primitive type!\");\n\n            channelType = _channelType;\n            numberOfChannels = channelTypes.Length;\n        }\n\n        /// <summary>\n        /// Determines whether the object is equal compared to the specified object. \n        /// A default comparison is used. Please see overloads.\n        /// </summary>\n        /// <param name=\"other\">Other object.</param>\n        /// <returns>True if two objects are equal, false otherwise.</returns>\n        public bool Equals(ColorInfo other)\n        {\n            return Equals(other, ComparableParts.Default);\n        }\n\n        /// <summary>\n        /// Indicates what parts of color info should be compared.\n        /// </summary>\n        [Flags]\n        public enum ComparableParts\n        {\n            /// <summary>\n            /// Checks color depth type\n            /// </summary>\n            Depth = 0x1,\n            /// <summary>\n            /// Checks if one color can be casted to other (if colors are binary compatible).\n            /// </summary>\n            BinaryCompatible = 0x3, \n            /// <summary>\n            /// Checks color type and depth type (if it is true all other properties are equal as well)\n            /// </summary>\n            Default =  0x4\n        }\n\n        /// <summary>\n        /// Compares two color infos.\n        /// </summary>\n        /// <param name=\"other\">Other color info.</param>\n        /// <param name=\"cParts\">Indicates what to compare. Default is: ComparableParts.Default. </param>\n        /// <returns></returns>\n        public bool Equals(ColorInfo other, ComparableParts cParts)\n        {\n            if(cParts == ComparableParts.Default)\n            {\n                return this.ColorType == other.ColorType && \n                       this.ChannelType == other.ChannelType;\n            }\n\n            if (cParts == ComparableParts.BinaryCompatible)\n            {\n                var castable = (this.ChannelCount == other.ChannelCount) && (this.ChannelType == other.ChannelType);\n                return castable;\n            }\n\n            if (cParts == ComparableParts.Depth)\n            { \n                var depth = this.ChannelType == other.ChannelType;\n                return depth;\n            }\n\n            throw new Exception(\"Unknown comparison!\");\n        }\n\n        /// <summary>\n        /// Get string representation.\n        /// </summary>\n        /// <returns>String</returns>\n        public override string ToString()\n        {\n            return String.Format(\"<{0}, {1}>\", this.ColorType.Name, this.ChannelType.Name);\n        }\n    }\n\n    /// <summary>\n    /// Provides extensions for color to array conversion.\n    /// </summary>\n    public static class ColorToArrayExtensions\n    {\n        /// <summary>\n        /// Converts color to array of type <typeparamref name=\"TDepth\"/>.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel type.</typeparam>\n        /// <param name=\"color\">Color</param>\n        /// <returns>Array whose length is the same as color's number of channels.</returns>\n        public static TDepth[] ColorToArray<TColor, TDepth>(this TColor color)\n            where TColor : IColor\n            where TDepth : struct\n        {\n            var fields = typeof(TColor).GetFields(BindingFlags.Public | ~BindingFlags.Static);\n\n            TDepth[] arr = new TDepth[fields.Length];\n\n            for (int i = 0; i < fields.Length; i++)\n            {\n                var rawVal = fields[i].GetValue(color);\n                arr[i] = (TDepth)Convert.ChangeType(rawVal, typeof(TDepth));\n            }\n\n            return arr;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/ColorTypeConversions/ColorSpaces/Bgr.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n      /// <summary>\n    /// Represents Bgr color type of type <typeparam name=\"T\">color depth</typeparam>.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Bgr<T> : IColor3<T>\n        where T : unmanaged\n    {\n        /// <summary>\n        /// Creates new Bgr color.\n        /// </summary>\n        /// <param name=\"b\">Blue</param>\n        /// <param name=\"g\">Green</param>\n        /// <param name=\"r\">Red</param>\n        public Bgr(T b, T g, T r)\n        {\n            this.B = b;\n            this.G = g;\n            this.R = r;\n        }\n\n        /// <summary>\n        /// Gets or sets the blue component.\n        /// </summary>\n        public T B;\n        /// <summary>\n        /// Gets or sets the green component.\n        /// </summary>\n        public T G;\n        /// <summary>\n        /// Gets or sets the red component.\n        /// </summary>\n        public T R;\n\n        /// <summary>\n        /// Gets the string color representation.\n        /// </summary>\n        /// <returns>String color representation.</returns>\n        public override string ToString()\n        {\n            return string.Format(\"B: {0}, G: {1}, R: {2}\", B, G, R);\n        }\n\n        /// <summary>\n        /// Gets the index of the blue component.\n        /// </summary>\n        public const int IdxB = 0;\n        /// <summary>\n        /// Gets the index of the green component.\n        /// </summary>\n        public const int IdxG = 1;\n        /// <summary>\n        /// Gets the index of the red component.\n        /// </summary>\n        public const int IdxR = 2;\n\n        /// <summary>\n        /// Gets the 8-bit red color.\n        /// </summary>\n        public static Bgr<byte> Red { get { return new Bgr<byte> { B = 0, G = 0, R = byte.MaxValue }; } }\n        /// <summary>\n        /// Gets the 8-bit blue color.\n        /// </summary>\n        public static Bgr<byte> Blue { get { return new Bgr<byte> { B = byte.MaxValue, G = 0, R = 0 }; } }\n        /// <summary>\n        /// Gets the 8-bit green color.\n        /// </summary>\n        public static Bgr<byte> Green { get { return new Bgr<byte> { B = 0, G = byte.MaxValue, R = 0 }; } }\n        /// <summary>\n        /// Gets the 8-bit black color.\n        /// </summary>\n        public static Bgr<byte> Black { get { return new Bgr<byte> { B = 0, G = 0, R = 0 }; } }\n        /// <summary>\n        /// Gets the 8-bit white color.\n        /// </summary>\n        public static Bgr<byte> White { get { return new Bgr<byte> { B = byte.MaxValue, G = byte.MaxValue, R = byte.MaxValue }; } }\n\n        /// <summary>\n        /// Converts 8-bit Bgr to 8-bit gray intensity. \n        /// </summary>\n        /// <param name=\"bgr\">Source color.</param>\n        /// <param name=\"gray\">Destination color.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Convert(Bgr<byte> bgr, ref Gray<byte> gray)\n        {\n            int val = ((bgr.R << 1) +           //2 * red\n                       (bgr.G << 2) + bgr.G +  //5 * green\n                        bgr.B                   //1 * blue\n\n                      ) >> 3;                   //divide by 8\n\n            gray.Intensity = (byte)val;\n        }\n\n        /// <summary>\n        /// Converts 8-bit Bgr to 8-bit Bgra. \n        /// </summary>\n        /// <param name=\"bgr\">Source color.</param>\n        /// <param name=\"bgra\">Destination color.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Convert(Bgr<byte> bgr, ref Bgra<byte> bgra)\n        {\n            bgra.B = bgr.B;\n            bgra.G = bgr.G;\n            bgra.R = bgr.R;\n            bgra.A = System.Byte.MaxValue;\n        }\n\n        /// <summary>\n        /// Converts 8-bit Bgr to 8-bit Bgra. \n        /// </summary>\n        /// <param name=\"bgr\">Source color.</param>\n        /// <param name=\"bgra\">Destination color.</param>\n        /// <param name=\"opacity\">Opacity.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Convert(Bgr<byte> bgr, ref Bgra<byte> bgra, byte opacity = System.Byte.MaxValue)\n        {\n            bgra.B = bgr.B;\n            bgra.G = bgr.G;\n            bgra.R = bgr.R;\n            bgra.A = opacity;\n        }\n\n        /// <summary>\n        /// Converts 8-bit Bgr to 8-bit Hsv color. Value range for 8-bit HSv color is  [0..180].\n        /// </summary>\n        /// <param name=\"bgr\">Source color.</param>\n        /// <param name=\"hsv\">Destination color.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Convert(Bgr<byte> bgr, ref Hsv<byte> hsv)\n        {\n            byte rgbMin, rgbMax;\n\n            rgbMin = bgr.R < bgr.G ? (bgr.R < bgr.B ? bgr.R : bgr.B) : (bgr.G < bgr.B ? bgr.G : bgr.B);\n            rgbMax = bgr.R > bgr.G ? (bgr.R > bgr.B ? bgr.R : bgr.B) : (bgr.G > bgr.B ? bgr.G : bgr.B);\n\n            hsv.V = rgbMax;\n            if (hsv.V == 0)\n            {\n                hsv.H = 0;\n                hsv.S = 0;\n                return;\n            }\n\n            hsv.S = (byte)(255 * (rgbMax - rgbMin) / rgbMax);\n            if (hsv.S == 0)\n            {\n                hsv.H = 0;\n                return;\n            }\n\n            int hue = 0;\n            if (rgbMax == bgr.R)\n            {\n                hue = 0 + 60 * (bgr.G - bgr.B) / (rgbMax - rgbMin);\n                if (hue < 0)\n                    hue += 360;\n            }\n            else if (rgbMax == bgr.G)\n            {\n                hue = 120 + 60 * (bgr.B - bgr.R) / (rgbMax - rgbMin);\n            }\n            else //rgbMax == bgr.B\n            {\n                hue = 240 + 60 * (bgr.R - bgr.G) / (rgbMax - rgbMin);\n            }\n\n            hsv.H = (byte)(hue / 2); //scale [0-360] . [0-180] (only needed for byte!)\n\n            //Debug.Assert(hue >= 0 && hue <= 360);\n        }\n    }\n\n    /// <summary>\n    /// Provides extension conversion methods for 8-bit Bgr type.\n    /// </summary>\n    public static class BgrColorConversionExtensions\n    {\n        /// <summary>\n        /// Converts 8-bit Bgr color to 8-bit gray.\n        /// </summary>\n        /// <param name=\"bgr\">8-bit Bgr color.</param>\n        /// <returns>8-bit gray</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Gray<byte> ToGray(this Bgr<byte> bgr)\n        {\n            Gray<byte> gray = default(Gray<byte>);\n            Bgr<byte>.Convert(bgr, ref gray);\n            return gray;\n        }\n\n        /// <summary>\n        /// Converts 8-bit Bgr color to 8-bit Hsv color.\n        /// </summary>\n        /// <param name=\"bgr\">8-bit Bgr color.</param>\n        /// <returns>8-bit Hsv color.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Hsv<byte> ToHsv(this Bgr<byte> bgr)\n        {\n            Hsv<byte> hsv = default(Hsv<byte>);\n            Bgr<byte>.Convert(bgr, ref hsv);\n            return hsv;\n        }\n    }\n\n    /// <summary>\n    /// Represents 8-bit Bgr color type.\n    /// <para>Its usage should be restricted only for unsafe pixel manipulation.</para>\n    /// </summary>\n    public struct Bgr8\n    {\n        /// <summary>\n        /// Gets or sets the blue component.\n        /// </summary>\n        public byte B;\n        /// <summary>\n        /// Gets or sets the green component.\n        /// </summary>\n        public byte G;\n        /// <summary>\n        /// Gets or sets the red component.\n        /// </summary>\n        public byte R;\n    }\n}\n"
  },
  {
    "path": "Source/Image/ColorTypeConversions/ColorSpaces/Bgra.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Represents Bgra color type of type <typeparam name=\"T\">depth</typeparam>.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Bgra<T> : IColor4<T>\n        where T: unmanaged\n    {\n        /// <summary>\n        /// Creates new Bgra color.\n        /// </summary>\n        /// <param name=\"b\">Blue</param>\n        /// <param name=\"g\">Green</param>\n        /// <param name=\"r\">Red</param>\n        /// <param name=\"a\">Alpha (transparency).</param>\n        public Bgra(T b, T g, T r, T a)\n        {\n            this.B = b;\n            this.G = g;\n            this.R = r;\n            this.A = a;\n        }\n\n        /// <summary>\n        /// Gets or sets the blue component.\n        /// </summary>\n        public T B;\n        /// <summary>\n        /// Gets or sets the green component.\n        /// </summary>\n        public T G;\n        /// <summary>\n        /// Gets or sets the red component.\n        /// </summary>\n        public T R;\n        /// <summary>\n        /// Gets or sets the alpha component.\n        /// </summary>\n        public T A;\n\n        /// <summary>\n        /// Gets the string color representation.\n        /// </summary>\n        /// <returns>String color representation.</returns>\n        public override string ToString()\n        {\n            return string.Format(\"B: {0}, G: {1}, R: {2}, A: {3}\", B, G, R, A);\n        }\n\n        /// <summary>\n        /// Gets the index of the blue component.\n        /// </summary>\n        public const int IdxB = 0;\n        /// <summary>\n        /// Gets the index of the green component.\n        /// </summary>\n        public const int IdxG = 1;\n        /// <summary>\n        /// Gets the index of the red component.\n        /// </summary>\n        public const int IdxR = 2;\n        /// <summary>\n        /// Gets the index of the alpha component.\n        /// </summary>\n        public const int IdxA = 3;\n\n        /// <summary>\n        /// Converts 8-bit Bgra to 8-bit Bgr color.\n        /// </summary>\n        /// <param name=\"bgra\">Source color.</param>\n        /// <param name=\"bgr\">Destination color.</param>\n        public static void Convert(Bgra<byte> bgra, ref Bgr<byte> bgr)\n        {\n            bgr.B = bgra.B;\n            bgr.G = bgra.G;\n            bgr.R = bgra.R;\n        }\n\n        /// <summary>\n        /// Converts 8-bit Bgra to 8-bit Gray.\n        /// </summary>\n        /// <param name=\"bgra\">Source color.</param>\n        /// <param name=\"gray\">Destination color.</param>\n        public static void Convert(Bgra<byte> bgra, ref Gray<byte> gray)\n        {\n            Bgr<byte> bgr = default(Bgr<byte>);\n            Convert(bgra, ref bgr);\n            Bgr<byte>.Convert(bgr, ref gray);\n        }\n    }\n\n    /// <summary>\n    /// Represents 8-bit Bgra color type.\n    /// <para>Its usage should be restricted only for unsafe pixel manipulation.</para>\n    /// </summary>\n    public struct Bgra8\n    {\n        /// <summary>\n        /// Gets or sets the blue component.\n        /// </summary>\n        public byte B;\n        /// <summary>\n        /// Gets or sets the green component.\n        /// </summary>\n        public byte G;\n        /// <summary>\n        /// Gets or sets the red component.\n        /// </summary>\n        public byte R;\n        /// <summary>\n        /// Gets or sets the alpha component.\n        /// </summary>\n        public byte A;\n    }\n\n}\n"
  },
  {
    "path": "Source/Image/ColorTypeConversions/ColorSpaces/Gray.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Represents gray color of type <typeparam name=\"T\">color depth</typeparam>.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Gray<T> : IColor<T>\n        where T: unmanaged\n    {\n        /// <summary>\n        /// Creates new gray color.\n        /// </summary>\n        /// <param name=\"intensity\">Intensity.</param>\n        public Gray(T intensity)\n        {\n            this.Intensity = intensity;\n        }\n\n        /// <summary>\n        /// Gets or sets the intensity.\n        /// </summary>\n        public T Intensity;\n\n        /// <summary>\n        /// Converts gray structure to <typeparamref name=\"T\"/> value.\n        /// </summary>\n        /// <param name=\"gray\">Gray color.</param>\n        /// <returns>Intensity.</returns>\n        public static implicit operator T(Gray<T> gray)\n        {\n            return gray.Intensity;\n        }\n\n        /// <summary>\n        /// Converts intensity of type <see cref=\"System.Double\"/> to Gray color.\n        /// </summary>\n        /// <param name=\"intensity\">Intensity.</param>\n        /// <returns>Gray color.</returns>\n        public static implicit operator Gray<T>(T intensity)\n        {\n            return new Gray<T>(intensity);\n        }\n\n        /// <summary>\n        /// Gets the string color representation.\n        /// </summary>\n        /// <returns>String color representation.</returns>\n        public override string ToString()\n        {\n            return string.Format(\"{0}\", Intensity);\n        }\n\n        /// <summary>\n        /// Converts 8-bit gray intensity to the 8-bit Bgr color.\n        /// </summary>\n        /// <param name=\"gray\">Source color.</param>\n        /// <param name=\"bgr\">Destination color.</param>\n        public static void Convert(Gray<T> gray, ref Bgr<T> bgr)\n        {\n            bgr.B = gray.Intensity;\n            bgr.G = gray.Intensity;\n            bgr.R = gray.Intensity;\n        }\n\n        /// <summary>\n        /// Converts 8-bit gray intensity to the 8-bit Bgra color.\n        /// </summary>\n        /// <param name=\"gray\">Source color.</param>\n        /// <param name=\"bgra\">Destination color.</param>\n        public static void Convert(Gray<byte> gray, ref Bgra<byte> bgra)\n        {\n            bgra.B = gray.Intensity;\n            bgra.G = gray.Intensity;\n            bgra.R = gray.Intensity;\n            bgra.A = System.Byte.MaxValue;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/ColorTypeConversions/ColorSpaces/Hsv.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Represents Hsv color type of type <typeparam name=\"T\">color depth</typeparam>.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Hsv<T>: IColor3<T>\n        where T: unmanaged\n    {\n        /// <summary>\n        /// Creates new Hsv color.\n        /// </summary>\n        /// <param name=\"hue\">Hue</param>\n        /// <param name=\"saturation\">Saturation</param>\n        /// <param name=\"value\">Value.</param>\n        public Hsv(T hue, T saturation, T value)\n        {\n            this.H = hue;\n            this.S = saturation;\n            this.V = value;\n        }\n\n        /// <summary>\n        /// Gets or sets hue.\n        /// </summary>\n        public T H;\n        /// <summary>\n        /// Gets or sets saturation.\n        /// </summary>\n        public T S;\n        /// <summary>\n        /// Gets or sets value.\n        /// </summary>\n        public T V;\n\n        /// <summary>\n        /// Gets the string color representation.\n        /// </summary>\n        /// <returns>String color representation.</returns>\n        public override string ToString()\n        {\n            return string.Format(\"H: {0}, S: {1}, V: {2}\", H, S, V);\n        }\n\n        /// <summary>\n        /// Gets the index of the hue component.\n        /// </summary>\n        public const int IdxH = 0;\n        /// <summary>\n        /// Gets the index of the saturation component.\n        /// </summary>\n        public const int IdxS = 1;\n        /// <summary>\n        /// Gets the index of the value component.\n        /// </summary>\n        public const int IdxV = 2;\n\n        /// <summary>\n        /// Converts 8-bit Hsv color to the 8-bit Bgr color.\n        /// </summary>\n        /// <param name=\"hsv\">Source color.</param>\n        /// <param name=\"bgr\">Destination color.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Convert(Hsv<byte> hsv, ref Bgr<byte> bgr)\n        {\n            if (hsv.S == 0)\n            {\n                bgr.R = hsv.V;\n                bgr.G = hsv.V;\n                bgr.B = hsv.V;\n                return;\n            }\n\n            int hue = hsv.H * 2; //move to [0-360 range] (only needed for byte!)\n\n            int hQuadrant = hue / 60; // Hue quadrant 0 - 5 (60deg)\n            int hOffset = hue % 60; // Hue position in quadrant\n            int vs = hsv.V * hsv.S;\n\n            byte p = (byte)(hsv.V - (vs / 255));\n            byte q = (byte)(hsv.V - (vs / 255 * hOffset) / 60);\n            byte t = (byte)(hsv.V - (vs / 255 * (60 - hOffset)) / 60);\n\n            switch (hQuadrant)\n            {\n                case 0:\n                    bgr.R = hsv.V; bgr.G = t; bgr.B = p;\n                    break;\n                case 1:\n                    bgr.R = q; bgr.G = hsv.V; bgr.B = p;\n                    break;\n                case 2:\n                    bgr.R = p; bgr.G = hsv.V; bgr.B = t;\n                    break;\n                case 3:\n                    bgr.R = p; bgr.G = q; bgr.B = hsv.V;\n                    break;\n                case 4:\n                    bgr.R = t; bgr.G = p; bgr.B = hsv.V;\n                    break;\n                default:\n                    bgr.R = hsv.V; bgr.G = p; bgr.B = q;\n                    break;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Provides extension conversion methods for 8-bit Hsv type.\n    /// </summary>\n    public static class HsvColorConversionExtensions\n    {\n        /// <summary>\n        /// Converts 8-bit Hsv color to 8-bit Bgr.\n        /// </summary>\n        /// <param name=\"hsv\">8-bit Hsv color.</param>\n        /// <returns>8-bit Bgr</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Bgr<byte> ToBgr(this Hsv<byte> hsv)\n        {\n            Bgr<byte> bgr = default(Bgr<byte>);\n            Hsv<byte>.Convert(hsv, ref bgr);\n            return bgr;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/ColorTypeConversions/ColorSpaces/IColor.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Default interface for color types.\n    /// </summary>\n    public interface IColor { }\n\n    /// <summary>\n    /// Default generic interface for color types.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public interface IColor<T> : IColor\n        where T : struct\n    { }\n\n    /// <summary>\n    /// Interface for 2 channel color type. (Used for compile-time restrictions)\n    /// </summary>\n    public interface IColor2 : IColor { }\n\n    /// <summary>\n    /// Generic interface for 2 channel color type. (Used for compile-time restrictions)\n    /// </summary>\n    public interface IColor2<T> : IColor2, IColor<T>\n         where T : struct\n    { }\n\n    /// <summary>\n    /// Interface for 3 channel color type. (Used for compile-time restrictions)\n    /// </summary>\n    public interface IColor3 : IColor { }\n\n    /// <summary>\n    /// Generic interface for 3 channel color type. (Used for compile-time restrictions)\n    /// </summary>\n    /// <typeparam name=\"T\">Channel type.</typeparam>\n    public interface IColor3<T> : IColor3, IColor<T>\n         where T : struct\n    { }\n\n    /// <summary>\n    /// Interface for 4 channel color type. (Used for compile-time restrictions)\n    /// </summary>\n    public interface IColor4 : IColor { }\n\n    /// <summary>\n    /// Generic interface for 4 channel color type. (Used for compile-time restrictions)\n    /// </summary>\n    /// <typeparam name=\"T\">Channel type.</typeparam>\n    public interface IColor4<T> : IColor4, IColor<T>\n         where T : struct\n    { }\n}\n"
  },
  {
    "path": "Source/Image/ColorTypeConversions/ColorSpaces/Rgb.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Represents Rgb color type of type <typeparam name=\"T\">color depth</typeparam>.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Rgb<T> : IColor3<T>\n        where T : unmanaged\n    {\n        /// <summary>\n        /// Creates new Rgb color.\n        /// </summary>\n        /// <param name=\"r\">Red</param>\n        /// <param name=\"g\">Green</param>\n        /// <param name=\"b\">Blue</param>\n        public Rgb(T r, T g, T b)\n        {\n            this.R = r;\n            this.G = g;\n            this.B = b;\n        }\n    \n        /// <summary>\n        /// Gets or sets the red component.\n        /// </summary>\n        public T R;\n        /// <summary>\n        /// Gets or sets the green component.\n        /// </summary>\n        public T G;\n        /// <summary>\n        /// Gets or sets the blue component.\n        /// </summary>\n        public T B;\n\n        /// <summary>\n        /// Gets the string color representation.\n        /// </summary>\n        /// <returns>String color representation.</returns>\n        public override string ToString()\n        {\n            return string.Format(\"R: {0}, G: {1}, B: {2}\", R, G, B);\n        }\n\n        /// <summary>\n        /// Gets the index of the red component.\n        /// </summary>\n        public const int IdxR = 0;\n        /// <summary>\n        /// Gets the index of the green component.\n        /// </summary>\n        public const int IdxG = 1;\n        /// <summary>\n        /// Gets the index of the blue component.\n        /// </summary>\n        public const int IdxB = 2;\n\n        /// <summary>\n        /// Converts 8-bit Rgb to 8-bit Bgr. \n        /// </summary>\n        /// <param name=\"rgb\">Source color.</param>\n        /// <param name=\"bgr\">Destination color.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Convert(Rgb<byte> rgb, ref Bgr<byte> bgr)\n        {\n            rgb.R = bgr.R;\n            rgb.G = bgr.G;\n            rgb.B = bgr.B;\n        }\n    }\n\n    /// <summary>\n    /// Represents 8-bit Rgb color type.\n    /// <para>Its usage should be restricted only for unsafe pixel manipulation.</para>\n    /// </summary>\n    public struct Rgb8\n    {\n        /// <summary>\n        /// Gets or sets the red component.\n        /// </summary>\n        public byte R;\n        /// <summary>\n        /// Gets or sets the green component.\n        /// </summary>\n        public byte G;\n        /// <summary>\n        /// Gets or sets the blue component.\n        /// </summary>\n        public byte B;\n    }\n}"
  },
  {
    "path": "Source/Image/ColorTypeConversions/Converters/ColorConversionExtensions.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\nusing System;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides color conversion extension methods.\n    /// </summary>\n    public static class ColorConversionExtensions\n    {\n        #region Gray color conversion\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"grayIm\">Source image.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgr<byte>[,] ToBgr(this Gray<byte>[,] grayIm)\n        {\n            return grayIm.Convert<Gray<byte>, Bgr<byte>>(Gray<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"grayIm\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgr<byte>[,] ToBgr(this Gray<byte>[,] grayIm, Rectangle area)\n        {\n            return grayIm.Convert<Gray<byte>, Bgr<byte>>(Gray<byte>.Convert, area);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"grayIm\">Source image.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgra<byte>[,] ToBgra(this Gray<byte>[,] grayIm)\n        {\n            return grayIm.Convert<Gray<byte>, Bgra<byte>>(Gray<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"grayIm\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgra<byte>[,] ToBgra(this Gray<byte>[,] grayIm, Rectangle area)\n        {\n            return grayIm.Convert<Gray<byte>, Bgra<byte>>(Gray<byte>.Convert, area);\n        }\n\n        #endregion\n\n        #region Bgr color conversion\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgra<byte>[,] ToBgra(this Bgr<byte>[,] image)\n        {\n            return image.Convert<Bgr<byte>, Bgra<byte>>(Bgr<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgra<byte>[,] ToBgra(this Bgr<byte>[,] image, Rectangle area)\n        {\n            return image.Convert<Bgr<byte>, Bgra<byte>>(Bgr<byte>.Convert, area);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <returns>image with converted color.</returns>\n        public static Gray<byte>[,] ToGray(this Bgr<byte>[,] image)\n        {\n            return image.Convert<Bgr<byte>, Gray<byte>>(Bgr<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>image with converted color.</returns>\n        public static Gray<byte>[,] ToGray(this Bgr<byte>[,] image, Rectangle area)\n        {\n            return image.Convert<Bgr<byte>, Gray<byte>>(Bgr<byte>.Convert, area);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <returns>image with converted color.</returns>\n        public static Hsv<byte>[,] ToHsv(this Bgr<byte>[,] image)\n        {\n            return image.Convert<Bgr<byte>, Hsv<byte>>(Bgr<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>image with converted color.</returns>\n        public static Hsv<byte>[,] ToHsv(this Bgr<byte>[,] image, Rectangle area)\n        {\n            return image.Convert<Bgr<byte>, Hsv<byte>>(Bgr<byte>.Convert, area);\n        }\n\n        #endregion\n\n        #region Rgb color conversion\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgr<byte>[,] ToBgr(this Rgb<byte>[,] image)\n        {\n            return image.Convert<Rgb<byte>, Bgr<byte>>(Rgb<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgr<byte>[,] ToBgr(this Rgb<byte>[,] image, Rectangle area)\n        {\n            return image.Convert<Rgb<byte>, Bgr<byte>>(Rgb<byte>.Convert, area);\n        }\n\n        #endregion\n\n        #region Bgra color conversion\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <returns>Image with converted color.</returns>\n        public static Bgr<byte>[,] ToBgr(this Bgra<byte>[,] image)\n        {\n            return image.Convert<Bgra<byte>, Bgr<byte>>(Bgra<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>Image with converted color.</returns>\n        public static Bgr<byte>[,] ToBgr(this Bgra<byte>[,] image, Rectangle area)\n        {\n            return image.Convert<Bgra<byte>, Bgr<byte>>(Bgra<byte>.Convert, area);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <returns>Image with converted color.</returns>\n        public static Gray<byte>[,] ToGray(this Bgra<byte>[,] image)\n        {\n            return image.Convert<Bgra<byte>, Gray<byte>>(Bgra<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>Image with converted color.</returns>\n        public static Gray<byte>[,] ToGray(this Bgra<byte>[,] image, Rectangle area)\n        {\n            return image.Convert<Bgra<byte>, Gray<byte>>(Bgra<byte>.Convert, area);\n        }\n        #endregion\n\n        #region Hsv color conversion\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgr<byte>[,] ToBgr(this Hsv<byte>[,] image)\n        {\n            return image.Convert<Hsv<byte>, Bgr<byte>>(Hsv<byte>.Convert);\n        }\n\n        /// <summary>\n        /// Converts the source color to the destination color.\n        /// </summary>\n        /// <param name=\"image\">Source image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>image with converted color.</returns>\n        public static Bgr<byte>[,] ToGray(this Hsv<byte>[,] image, Rectangle area)\n        {\n            return image.Convert<Hsv<byte>, Bgr<byte>>(Hsv<byte>.Convert, area);\n        }\n\n        #endregion\n\n\n\n        #region Unmanaged image and array cloning (ToBgr(), ToBgra(), ToGray())\n\n        /// <summary>\n        /// Converts the specified image into Bgr managed image.\n        /// </summary>\n        /// <param name=\"image\">Bgr, Bgra or Gray type image.</param>\n        /// <returns>Bgr image or null if conversion can not be performed.</returns>\n        public static Bgr<byte>[,] ToBgr(this IImage image)\n        {\n            if (image is Image<Bgra<byte>>)\n            {\n                return (image as Image<Bgra<byte>>).Clone().ToBgr();\n            }\n            else if (image is Image<Bgr<byte>>)\n            {\n                return (image as Image<Bgr<byte>>).Clone();\n            }\n            else if (image is Image<Gray<byte>>)\n            {\n                return (image as Image<Gray<byte>>).Clone().ToBgr();\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Converts the specified image into Bgra managed image.\n        /// </summary>\n        /// <param name=\"image\">Bgr, Bgra or Gray type image.</param>\n        /// <returns>Bgra image or null if conversion can not be performed.</returns>\n        public static Bgra<byte>[,] ToBgra(this IImage image)\n        {\n            if (image is Image<Bgra<byte>>)\n            {\n                return (image as Image<Bgra<byte>>).Clone();\n            }\n            else if (image is Image<Bgr<byte>>)\n            {\n                return (image as Image<Bgr<byte>>).Clone().ToBgra();\n            }\n            else if (image is Image<Gray<byte>>)\n            {\n                return (image as Image<Gray<byte>>).Clone().ToBgra();\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Converts the specified image into gray managed image.\n        /// </summary>\n        /// <param name=\"image\">Bgr, Bgra or Gray type image.</param>\n        /// <returns>Gray image or null if conversion can not be performed.</returns>\n        public static Gray<byte>[,] ToGray(this IImage image)\n        {\n            if (image is Image<Bgra<byte>>)\n            {\n                return (image as Image<Bgra<byte>>).ToGray();\n            }\n            else if (image is Image<Bgr<byte>>)\n            {\n                return (image as Image<Bgr<byte>>).Clone().ToGray();\n            }\n            else if (image is Image<Gray<byte>>)\n            {\n                return (image as Image<Gray<byte>>).Clone();\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Converts the specified 2D array into Bgr managed image.\n        /// <para>If the specified array is the Bgr managed image, the source is returned.</para>\n        /// </summary>\n        /// <param name=\"array2D\">Bgr, Bgra or Gray type bitmap.</param>\n        /// <returns>Bgr image or null if conversion can not be performed.</returns>\n        public static Bgr<byte>[,] ToBgr(this Array array2D)\n        {\n            if (array2D is Bgra<byte>[,])\n            {\n                return ((Bgra<byte>[,])array2D).ToBgr();\n            }\n            else if (array2D is Bgr<byte>[,])\n            {\n                return ((Bgr<byte>[,])array2D);\n            }\n            else if (array2D is Gray<byte>[,])\n            {\n                return ((Gray<byte>[,])array2D).ToBgr();\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Converts the specified 2D array into Bgra managed image.\n        /// <para>If the specified array is the Bgra managed image, the source is returned.</para>\n        /// </summary>\n        /// <param name=\"array2D\">Bgra, Bgr or Gray type bitmap.</param>\n        /// <returns>Bgra image or null if conversion can not be performed.</returns>\n        public static Bgra<byte>[,] ToBgra(this Array array2D)\n        {\n            if (array2D is Bgra<byte>[,])\n            {\n                return (Bgra<byte>[,])array2D;\n            }\n            else if (array2D is Bgr<byte>[,])\n            {\n                return ((Bgr<byte>[,])array2D).ToBgra();\n            }\n            else if (array2D is Gray<byte>[,])\n            {\n                return ((Gray<byte>[,])array2D).ToBgra();\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Converts the specified 2D array into gray managed image.\n        /// <para>If the specified array is the gray managed image, the source is returned.</para>\n        /// </summary>\n        /// <param name=\"array2D\">Bgra, Bgr or Gray type bitmap.</param>\n        /// <returns>Gray image or null if conversion can not be performed.</returns>\n        public static Gray<byte>[,] ToGray(this Array array2D)\n        {\n            if (array2D is Bgra<byte>[,])\n            {\n                return ((Bgra<byte>[,])array2D).ToGray();\n            }\n            else if (array2D is Bgr<byte>[,])\n            {\n                return ((Bgr<byte>[,])array2D).ToGray();\n            }\n            else if (array2D is Gray<byte>[,])\n            {\n                return (Gray<byte>[,])array2D;\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Source/Image/Extensions/BasicExtensions.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\nusing System;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides basic image extensions for a two-dimensional array.\n    /// </summary>\n    public static class ArrayImageBasicExtensions\n    {\n        /// <summary>\n        /// Gets image width.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <returns>The image width.</returns>\n        public static int Width<T>(this T[,] image)\n        {\n            return image.GetLength(1);\n        }\n\n        /// <summary>\n        /// Gets image height.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <returns>The image height.</returns>\n        public static int Height<T>(this T[,] image)\n        {\n            return image.GetLength(0);\n        }\n\n        /// <summary>\n        /// Gets image size.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <returns>The image size.</returns>\n        public static Size Size<T>(this T[,] image)\n        {\n            return new Size(image.Width(), image.Height());\n        }\n\n        /// <summary>\n        /// Pins the array and returns the corresponding generic image.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\n        /// <param name=\"array\">The array to lock.</param>\n        /// <returns>The generic image which shares data with the pined array.</returns>\n        public static Image<TColor> Lock<TColor>(this TColor[,] array)\n            where TColor: unmanaged\n        {\n            return Image<TColor>.Lock(array);\n        }\n\n        /// <summary>\n        /// Pins the array and returns the corresponding generic image of a specified portion.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\n        /// <param name=\"array\">The array to lock.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>The generic image which shares data with the pined array.</returns>\n        public static Image<TColor> Lock<TColor>(this TColor[,] array, Rectangle area)\n          where TColor: unmanaged\n        {\n            return Image<TColor>.Lock(array).GetSubRect(area);\n        }\n\n        /// <summary>\n        /// Sets all elements of the array to the default value.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array to clear.</param>\n        public static void Clear<T>(this T[,] array)\n            where T: unmanaged\n        {\n            Array.Clear(array, 0, array.Length);\n        }\n\n        /// <summary>\n        /// Performs deep cloning of the specified array.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array.</param>\n        /// <returns>Cloned array.</returns>\n        public static T[,] Clone<T>(this T[,] array)\n            where T: unmanaged\n        {\n            return (T[,])array.Clone();\n        }\n\n        /// <summary>\n        /// Creates new array of the same size as the source array.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array.</param>\n        /// <returns>New empty array.</returns>\n        public static T[,] CopyBlank<T>(this T[,] array)\n        {\n            return new T[array.Height(), array.Width()];\n        }\n\n        /// <summary>\n        /// Gets the element info of the specified array.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Element type.</typeparam>\n        /// <param name=\"source\">Array.</param>\n        /// <returns>Array element info.</returns>\n        public static ColorInfo ColorInfo<TColor>(this TColor[,] source)\n            where TColor: unmanaged\n        {\n            return DotImaging.ColorInfo.GetInfo<TColor>();\n        }\n\n        /// <summary>\n        /// Calculates image stride for the specified alignment.\n        /// </summary>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"allignment\">Data alignment.</param>\n        /// <returns>Image stride.</returns>\n        public static int CalculateStride<TImage>(this TImage image, int allignment = 4)\n            where TImage: IImage\n        {\n            int stride = image.Width * image.ColorInfo.Size;\n\n            if (allignment != 0 &&\n                stride % allignment != 0)\n            {\n                stride += (allignment - (stride % allignment));\n            }\n\n            return stride;\n        }\n\n        /// <summary>\n        /// Applies the specified conversion function to each source pixel, producing the destination image.\n        /// </summary>\n        /// <typeparam name=\"TSrc\">Source element type.</typeparam>\n        /// <typeparam name=\"TDst\">Destination element type.</typeparam>\n        /// <param name=\"source\">Source array.</param>\n        /// <param name=\"convert\">Pixel conversion function.</param>\n        /// <returns>Destination array.</returns>\n        public static TDst[,] Convert<TSrc, TDst>(this TSrc[,] source, Func<TSrc, TDst> convert)\n        {\n            Size imSize = source.Size();\n            TDst[,] dest = new TDst[imSize.Height, imSize.Width];\n\n            ParallelLauncher.Launch(thread => \n            {\n                dest[thread.Y, thread.X] = convert(source[thread.Y, thread.X]);\n            }, \n            source.Width(), source.Height());\n\n            return dest;\n        }\n\n        /// <summary>\n        /// Applies the specified conversion function to each source pixel, producing the destination image.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"source\">Source array.</param>\n        /// <param name=\"apply\">Pixel conversion function.</param>\n        /// <param name=\"inPlace\">\n        /// True to apply the function in place, false otherwise.\n        /// <para>If true the result image is the same as source image.</para>\n        /// </param>\n        /// <returns>Destination array.</returns>\n        public static T[,] Apply<T>(this T[,] source, Func<T, T> apply, bool inPlace = false)\n        {\n            Size imSize = source.Size();\n            T[,] dest = inPlace ? source : new T[imSize.Height, imSize.Width];\n\n            ParallelLauncher.Launch(thread =>\n            {\n                dest[thread.Y, thread.X] = apply(source[thread.Y, thread.X]);\n            },\n            source.Width(), source.Height());\n\n            return dest;\n        }\n\n        #region Set value\n\n        /// <summary>\n        /// Sets the specified value for each element of the array.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array with value type elements.</param>\n        /// <param name=\"value\">Value to set.</param>\n        public static void SetValue<T>(this T[,] array, T value)\n            where T : struct\n        {\n            ParallelLauncher.Launch((thread) =>\n            {\n                array[thread.Y, thread.X] = value;\n            },\n            array.Width(), array.Height());\n        }\n\n        /// <summary>\n        /// Sets the specified value for each element of the array.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array with value type elements.</param>\n        /// <param name=\"value\">Value to set.</param>\n        /// <param name=\"area\">Working area.</param>\n        public static void SetValue<T>(this T[,] array, T value, Rectangle area)\n            where T : struct\n        {\n            ParallelLauncher.Launch((thread) =>\n            {\n                array[thread.Y + area.Y, thread.X + area.X] = value;\n            },\n            area.Width, area.Height);\n        }\n\n        /// <summary>\n        /// Sets the specified value for only those element of the array where the mask is true.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array with value type elements.</param>\n        /// <param name=\"value\">Value to set.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <param name=\"mask\">Mask.</param>\n        public static void SetValue<T>(this T[,] array, T value, Rectangle area, bool[,] mask)\n        {\n            if (array.Size() != mask.Size())\n                throw new ArgumentException(\"Array and mask must have the same size.\");\n\n            ParallelLauncher.Launch((thread) =>\n            {\n                if (mask[thread.Y + area.Y, thread.X + area.X])\n                    array[thread.Y + area.Y, thread.X + area.X] = value;\n            },\n            area.Width, area.Height);\n        }\n\n        /// <summary>\n        /// Sets the specified value for only those element of the array where the mask is non-zero.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array with value type elements.</param>\n        /// <param name=\"value\">Value to set.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <param name=\"mask\">Mask.</param>\n        public static void SetValue<T>(this T[,] array, T value, Rectangle area, Gray<byte>[,] mask)\n        {\n            if (array.Size() != mask.Size())\n                throw new ArgumentException(\"Array and mask must have the same size.\");\n\n            ParallelLauncher.Launch((thread) =>\n            {\n                if (mask[thread.Y + area.Y, thread.X + area.X] != 0)\n                    array[thread.Y + area.Y, thread.X + area.X] = value;\n            },\n            area.Width, area.Height);\n        }\n\n        /// <summary>\n        /// Sets the specified value for only those element of the array where the mask is non-zero.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array with value type elements.</param>\n        /// <param name=\"value\">Value to set.</param>\n        /// <param name=\"mask\">Mask.</param>\n        public static void SetValue<T>(this T[,] array, T value, Gray<byte>[,] mask)\n        {\n            if (array.Size() != mask.Size())\n                throw new ArgumentException(\"Array and mask must have the same size.\");\n\n            ParallelLauncher.Launch((thread) =>\n            {\n                if (mask[thread.Y, thread.X] != 0)\n                    array[thread.Y, thread.X] = value;\n            },\n            array.Width(), array.Height());\n        }\n\n        /// <summary>\n        /// Sets the specified value for only those element of the array where the mask is true.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array with value type elements.</param>\n        /// <param name=\"value\">Value to set.</param>\n        /// <param name=\"mask\">Mask.</param>\n        public static void SetValue<T>(this T[,] array, T value, bool[,] mask)\n        {\n            if (array.Size() != mask.Size())\n                throw new ArgumentException(\"Array and mask must have the same size.\");\n\n            ParallelLauncher.Launch((thread) =>\n            {\n                if (mask[thread.Y, thread.X])\n                    array[thread.Y, thread.X] = value;\n            },\n            array.Width(), array.Height());\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Source/Image/Extensions/ChannelMerger.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Collections.Generic;\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides channel merge extensions.\n    /// </summary>\n    public static class ChannelMerger\n    {\n        /// <summary>\n        /// Combines provided channels into single image with interleaved channels.\n        /// </summary>\n        /// <typeparam name=\"TSrcColor\">Source color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel depth type.</typeparam>\n        /// <param name=\"channels\">Channel collection.</param>\n        /// <param name=\"channelIndices\">Channel indicies. If null, all channels are taken.</param>\n        /// <returns>Image.</returns>\n        public static TSrcColor[,] MergeChannels<TSrcColor, TDepth>(this IList<Gray<TDepth>[,]> channels, params int[] channelIndices)\n            where TSrcColor : unmanaged, IColor<TDepth>\n            where TDepth : unmanaged\n        {\n            var area = new Rectangle(new Point(), channels[0].Size());\n            return channels.MergeChannels<TSrcColor, TDepth>(area, channelIndices);\n        }\n\n        /// <summary>\n        /// Combines provided channels into single image with interleaved channels.\n        /// </summary>\n        /// <typeparam name=\"TSrcColor\">Source color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel depth type.</typeparam>\n        /// <param name=\"channels\">Channel collection.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <param name=\"channelIndices\">Channel indicies. If null, all channels are taken.</param>\n        /// <returns>Image.</returns>\n        public static TSrcColor[,] MergeChannels<TSrcColor, TDepth>(this IList<Gray<TDepth>[,]> channels, Rectangle area, params int[] channelIndices)\n            where TSrcColor : unmanaged, IColor<TDepth>\n            where TDepth : unmanaged\n        {\n            TSrcColor[,] image = new TSrcColor[area.Height, area.Width];\n\n            using (var im = image.Lock())\n            {\n                for (int i = 0; i < channelIndices.Length; i++)\n                {\n                    using (var ch = channels[i].Lock())\n                    {\n                        replaceChannel<TSrcColor, TDepth>(im, ch.GetSubRect(area), channelIndices[i]);\n                    }\n                }\n            }\n            return image;\n        }\n\n        /// <summary>\n        /// Replaces the selected image channel with the specified channel.\n        /// </summary>\n        /// <typeparam name=\"TSrcColor\">Source color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel depth type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"channel\">Channel.</param>\n        /// <param name=\"channelIndex\">Index of a channel to replace.</param>\n        public static void ReplaceChannel<TSrcColor, TDepth>(this TSrcColor[,] image, Gray<TDepth>[,] channel, int channelIndex)\n            where TSrcColor : unmanaged, IColor<TDepth>\n            where TDepth : unmanaged\n        {\n            using (var im = image.Lock())\n            using (var ch = channel.Lock())\n            {\n                replaceChannel<TSrcColor, TDepth>(im, ch, channelIndex);\n            }\n        }\n\n        private static unsafe void replaceChannel<TSrcColor, TDepth>(Image<TSrcColor> image, Image<Gray<TDepth>> channel, int channelIndex)\n            where TSrcColor : unmanaged, IColor<TDepth>\n            where TDepth : unmanaged\n        {\n            int width = image.Width;\n            int height = image.Height;\n\n            int channelSize = image.ColorInfo.ChannelSize;\n            int colorSize = image.ColorInfo.Size;\n\n            byte* srcPtr = (byte*)channel.ImageData;\n            byte* dstPtr = (byte*)image.ImageData + channelIndex * image.ColorInfo.ChannelSize;;\n\n            for (int row = 0; row < height; row++)\n            {\n                byte* srcColPtr = srcPtr;\n                byte* dstColPtr = dstPtr;\n                for (int col = 0; col < width; col++)\n                {\n                    /********** copy channel byte-per-byte ************/\n                    for (int partIdx = 0; partIdx < channelSize; partIdx++)\n                    {\n                        dstPtr[partIdx] = srcColPtr[partIdx];\n                    }\n\n                    srcColPtr += channelSize; //move to the next column\n                    dstColPtr += colorSize;\n                    /********** copy channel byte-per-byte ************/\n                }\n\n                srcPtr += channel.Stride;\n                dstPtr += image.Stride;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Extensions/ChannelSplitter.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Linq;\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides channel splitting extensions.\n    /// </summary>\n    public static class ChannelSplitter\n    {\n        /// <summary>\n        /// Extracts the specified image channels.\n        /// </summary>\n        /// <typeparam name=\"TSrcColor\">Source color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel depth type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"channelIndices\">Channel indicies to extract. If null, all channels are extracted.</param>\n        /// <returns>Channel collection.</returns>\n        public static unsafe Gray<TDepth>[][,] SplitChannels<TSrcColor, TDepth>(this TSrcColor[,] image, params int[] channelIndices)\n            where TSrcColor : unmanaged, IColor<TDepth>\n            where TDepth : unmanaged\n        { \n            Rectangle area = new Rectangle(0, 0, image.Width(), image.Height());\n            return image.SplitChannels<TSrcColor, TDepth>(area, channelIndices);\n        }\n\n        /// <summary>\n        /// Extracts the specified image channels.\n        /// </summary>\n        /// <typeparam name=\"TSrcColor\">Source color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel depth type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <param name=\"channelIndices\">Channel indicies to extract. If null, all channels are extracted.</param>\n        /// <returns>Channel collection.</returns>\n        public static unsafe Gray<TDepth>[][,] SplitChannels<TSrcColor, TDepth>(this TSrcColor[,] image, Rectangle area, params int[] channelIndices)\n            where TSrcColor: unmanaged, IColor<TDepth>\n            where TDepth: unmanaged\n        {\n            if (channelIndices == null || channelIndices.Length == 0)\n            {\n                channelIndices = Enumerable.Range(0, ColorInfo.GetInfo<TSrcColor>().ChannelCount).ToArray();\n            }\n\n            var channels = new Gray<TDepth>[channelIndices.Length][,];\n            for (int i = 0; i < channelIndices.Length; i++)\n\t\t\t{\n                channels[i] = GetChannel<TSrcColor, TDepth>(image, area, channelIndices[i]);\n\t\t\t}\n\n            return channels;\n        }\n\n        /// <summary>\n        /// Extracts a single image channel.\n        /// </summary>\n        /// <typeparam name=\"TSrcColor\">Source color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel depth type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"channelIndex\">Channel index.</param>\n        /// <returns>Extracted channel.</returns>\n        public static unsafe Gray<TDepth>[,] GetChannel<TSrcColor, TDepth>(this TSrcColor[,] image, int channelIndex)\n            where TSrcColor : unmanaged, IColor<TDepth>\n            where TDepth : unmanaged\n        {\n            Rectangle area = new Rectangle(0, 0, image.Width(), image.Height());\n            return image.GetChannel<TSrcColor, TDepth>(area, channelIndex);\n        }\n\n        /// <summary>\n        /// Extracts a single image channel.\n        /// </summary>\n        /// <typeparam name=\"TSrcColor\">Source color type.</typeparam>\n        /// <typeparam name=\"TDepth\">Channel depth type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <param name=\"channelIndex\">Channel index.</param>\n        /// <returns>Extracted channel.</returns>\n        public static unsafe Gray<TDepth>[,] GetChannel<TSrcColor, TDepth>(this TSrcColor[,] image, Rectangle area, int channelIndex)\n            where TSrcColor: unmanaged, IColor<TDepth>\n            where TDepth: unmanaged\n        {\n            int width = area.Width;\n            int height = area.Height;\n\n            var dest = new Gray<TDepth>[area.Height, area.Width];\n\n            using (var lockedImage = image.Lock())\n            using (var dstImg = dest.Lock())\n            {\n                var srcImg = lockedImage.GetSubRect(area);\n                int channelSize = srcImg.ColorInfo.ChannelSize;\n                int colorSize = srcImg.ColorInfo.Size;\n\n                byte* srcPtr = (byte*)srcImg.ImageData + channelIndex * srcImg.ColorInfo.ChannelSize;\n                byte* dstPtr = (byte*)dstImg.ImageData;\n\n                for (int row = 0; row < height; row++)\n                {\n                    byte* srcColPtr = srcPtr;\n                    byte* dstColPtr = dstPtr;\n                    for (int col = 0; col < width; col++)\n                    {\n                        /********** copy channel byte-per-byte ************/\n                        for (int partIdx = 0; partIdx < channelSize; partIdx++)\n                        {\n                            dstColPtr[partIdx] = srcColPtr[partIdx];\n                        }\n\n                        srcColPtr += colorSize; //move to the next column\n                        dstColPtr += channelSize;\n                        /********** copy channel byte-per-byte ************/\n                    }\n\n                    srcPtr += srcImg.Stride;\n                    dstPtr += dstImg.Stride;\n                }\n            }\n\n            return dest;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Extensions/Convert.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Element conversion delegate.\n    /// </summary>\n    /// <typeparam name=\"TSrc\">Source element type.</typeparam>\n    /// <typeparam name=\"TDst\">Destination element type.</typeparam>\n    /// <param name=\"source\">Source element.</param>\n    /// <param name=\"destination\">Destination element.</param>\n    public delegate void Convert<TSrc, TDst>(TSrc source, ref TDst destination)\n        where TSrc : unmanaged\n        where TDst : unmanaged;\n\n    /// <summary>\n    /// Provides generic element conversion extensions.\n    /// </summary>\n    public static class ConvertExtensions\n    {\n        /// <summary>\n        /// Converts each element of the array by using the specified conversion function.\n        /// </summary>\n        /// <typeparam name=\"TSrc\">Source element type.</typeparam>\n        /// <typeparam name=\"TDst\">Destination element type.</typeparam>\n        /// <param name=\"source\">Source array.</param>\n        /// <param name=\"convert\">Conversion function.</param>\n        /// <returns>Destination array.</returns>\n        public static TDst[,] Convert<TSrc, TDst>(this TSrc[,] source, Convert<TSrc, TDst> convert)\n            where TSrc : unmanaged\n            where TDst : unmanaged\n        {\n            var area = new Rectangle(0, 0, source.GetLength(1), source.GetLength(0));\n            return source.Convert<TSrc, TDst>(convert, area);\n        }\n\n        /// <summary>\n        /// Converts each element of the array by using the specified conversion function.\n        /// </summary>\n        /// <typeparam name=\"TSrc\">Source element type.</typeparam>\n        /// <typeparam name=\"TDst\">Destination element type.</typeparam>\n        /// <param name=\"source\">Source array.</param>\n        /// <param name=\"convert\">Conversion function.</param>\n        /// <param name=\"area\">Working area.</param>\n        public static TDst[,] Convert<TSrc, TDst>(this TSrc[,] source, Convert<TSrc, TDst> convert, Rectangle area)\n            where TSrc : unmanaged\n            where TDst : unmanaged\n        {\n            TDst[,] destination = new TDst[area.Height, area.Width];\n            var offset = area.Location;\n\n            ParallelLauncher.Launch(thread =>\n            {\n                convert(source[thread.Y + offset.Y, thread.X + offset.X], ref destination[thread.Y, thread.X]);\n            },\n            area.Width, area.Height);\n\n            return destination;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Extensions/Copy.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Drawing;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides methods for unsafe data copying as well as extensions for generic image and array cloning.\n    /// </summary>\n    public static class Copy\n    {\n        [DllImport(\"ntdll.dll\", CallingConvention = CallingConvention.Cdecl)]\n        private static unsafe extern IntPtr memcpy(IntPtr dst, IntPtr src, int count);\n\n        static Copy()\n        {\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\n                Copy.UnsafeCopy = (src, dst, count) => memcpy(dst, src, count);\n            else\n                Copy.UnsafeCopy = unsafeCopy_ElementByElement;\n        }\n\n\n        /// <summary>\n        /// Copy block of unmanaged memory. \n        /// </summary>\n        /// \n        /// <param name=\"src\">Source pointer.</param>\n        /// <param name=\"dst\">Destination pointer.</param>\n        /// <param name=\"count\">Memory block's length to copy.</param>\n        /// \n        /// <remarks><para>This function is required because of the fact that .NET does\n        /// not provide any way to copy unmanaged blocks, but provides only methods to\n        /// copy from unmanaged memory to managed memory and vise versa.</para></remarks>\n        public delegate void UnsafeCopyFunc(IntPtr src, IntPtr dst, int count);\n\n        /// <summary>\n        /// Copy block of unmanaged memory. \n        /// </summary>\n        public static readonly UnsafeCopyFunc UnsafeCopy;\n\n        /// <summary>\n        /// Copy block of unmanaged memory. \n        /// </summary>\n        /// \n        /// <param name=\"src\">Source pointer.</param>\n        /// <param name=\"dst\">Destination pointer.</param>\n        /// <param name=\"count\">Memory block's length to copy.</param>\n        /// \n        /// <remarks><para>This function is required because of the fact that .NET does\n        /// not provide any way to copy unmanaged blocks, but provides only methods to\n        /// copy from unmanaged memory to managed memory and vise versa.</para></remarks>\n        static unsafe void unsafeCopy_ElementByElement(IntPtr src, IntPtr dst, int count)  //Taken from AForge.NET and modified.\n        {\n            int countUint = count >> 2;\n            int countByte = count & 3;\n\n            uint* dstUint = (uint*)dst;\n            uint* srcUint = (uint*)src;\n\n            while (countUint-- != 0)\n            {\n                *dstUint++ = *srcUint++;\n            }\n\n            byte* dstByte = (byte*)dstUint;\n            byte* srcByte = (byte*)srcUint;\n\n            while (countByte-- != 0)\n            {\n                *dstByte++ = *srcByte++;\n            }\n        }\n\n        /// <summary>\n        /// Copies unmanaged data from the specified source to the specified destination patch.\n        /// </summary>\n        /// <param name=\"srcPtr\">Source pointer.</param>\n        /// <param name=\"destPtr\">Destination pointer.</param>\n        /// <param name=\"srcStride\">Source stride.</param>\n        /// <param name=\"destStride\">Destination stride.</param>\n        /// <param name=\"patchStride\">Amount of bytes per row to be copied (width for byte fields). (common: image width * color size)</param>\n        /// <param name=\"patchHeight\">Field's height.</param>\n        public unsafe static void UnsafeCopy2D(IntPtr srcPtr, IntPtr destPtr, int srcStride, int destStride, int patchStride, int patchHeight)\n        {\n            if (srcStride == destStride && srcStride == patchStride)\n                UnsafeCopy(srcPtr, destPtr, srcStride * patchHeight);\n            else\n            {\n                byte* srcImgPtr = (byte*)srcPtr;\n                byte* destImgPtr = (byte*)destPtr;\n\n                for (int i = 0; i < patchHeight; i++)\n                {\n                    UnsafeCopy((IntPtr)srcImgPtr, (IntPtr)destImgPtr, patchStride);\n\n                    srcImgPtr += srcStride;\n                    destImgPtr += destStride;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Copies unmanaged data from the specified source to the specified destination.\n        /// </summary>\n        /// <param name=\"srcPtr\">Source pointer.</param>\n        /// <param name=\"destPtr\">Destination pointer.</param>\n        /// <param name=\"srcStride\">Source stride.</param>\n        /// <param name=\"destStride\">Destination stride.</param>\n        /// <param name=\"destHeight\">Field's height.</param>\n        public unsafe static void UnsafeCopy2D(IntPtr srcPtr, IntPtr destPtr, int srcStride, int destStride, int destHeight)\n        {\n            UnsafeCopy2D(srcPtr, destPtr, srcStride, destStride, destStride, destHeight);\n        }\n\n        /// <summary>\n        /// Clones the portion of the provided array.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>Cloned portion of the array.</returns>\n        public static T[,] Clone<T>(this T[,] array, Rectangle area)\n            where T : unmanaged\n        {\n            //error handling in Lock(...)\n\n            var destination = new T[area.Height, area.Width];\n\n            using(var srcImg = array.Lock(area))\n            using (var dstImg = destination.Lock())\n            {\n                UnsafeCopy2D(srcImg.ImageData, dstImg.ImageData, srcImg.Stride, dstImg.Stride, dstImg.Height);\n            }\n\n            return destination;\n        }\n\n        /// <summary>\n        /// Clones the provided image.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"image\">Image.</param>\n        /// <returns>Cloned image.</returns>\n        public static T[,] Clone<T>(this Image<T> image)\n            where T : unmanaged\n        {\n            if (image == null)\n                return null;\n\n            //error handling in CopyTo(..)\n\n            var destination = new T[image.Height, image.Width];\n            CopyTo(image, destination);\n\n            return destination;\n        }\n\n        /// <summary>\n        /// Copies the specified source image to the destination image.\n        /// <para>Source and destination image must have the same size.</para>\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"source\">Source image.</param>\n        /// <param name=\"destination\">Destination image.</param>\n        public static void CopyTo<T>(this Image<T> source, Image<T> destination)\n            where T : unmanaged\n        {\n            if (source.Size != destination.Size)\n                throw new ArgumentException(\"Source dimension must be the same as destination dimension.\");\n\n            UnsafeCopy2D(source.ImageData, destination.ImageData, source.Stride, destination.Stride, destination.Height);\n        }\n\n        /// <summary>\n        /// Copies the specified source image to the destination image.\n        /// <para>Source and destination image must have the same size.</para>\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"source\">Source image.</param>\n        /// <param name=\"destination\">Destination image.</param>\n        public static void CopyTo<T>(this Image<T> source, T[,] destination)\n            where T: unmanaged\n        {\n            //error handling in CopyTo(..)\n\n            using (var dstImg = destination.Lock())\n            {\n                CopyTo(source, dstImg);\n            }\n        }\n\n        /// <summary>\n        /// Copies the specified source image to the destination image.\n        /// <para>Source and destination image must have the same size.</para>\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"source\">Source image.</param>\n        /// <param name=\"destination\">Destination image.</param>\n        /// <param name=\"destinationOffset\">Destination location.</param>\n        public static void CopyTo<T>(this T[,] source, T[,] destination, Point destinationOffset = default)\n            where T: unmanaged\n        {\n            var destRect = new Rectangle(destinationOffset, source.Size());\n\n            using (var srcImg = source.Lock())\n            using (var dstImg = destination.Lock(destRect))\n            {\n                UnsafeCopy2D(srcImg.ImageData, dstImg.ImageData, srcImg.Stride, dstImg.Stride, dstImg.Height);\n            }\n        }\n\n        /// <summary>\n        /// Copies the image source to the destination buffer. \n        /// If the buffer does not have the same size as the source image, or the buffer is null, the destination buffer will be recreated.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\n        /// <param name=\"source\">Source image.</param>\n        /// <param name=\"destinationBuffer\">destination buffer.</param>\n        public static void CopyToOrCreate<TColor>(this Image<TColor> source, ref TColor[,] destinationBuffer)\n            where TColor: unmanaged\n        {\n            if (source == null)\n            {\n                destinationBuffer = null;\n                return;\n            }\n\n            if (destinationBuffer == null ||\n               source.Width != destinationBuffer.Width() || source.Height != destinationBuffer.Height())\n            {\n                destinationBuffer = source.Clone();\n            }\n            else\n            {\n                source.CopyTo(destinationBuffer);\n            }\n        }\n\n        /// <summary>\n        /// Copies values from source to destination image using mask. Destination values where mask == 0 are not erased!.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Element type.</typeparam>\n        /// <param name=\"source\">Image.</param>\n        /// <param name=\"destination\">Destination image</param>\n        /// <param name=\"mask\">Mask. Color locations that need to be copied must be set to !=0 in mask.</param>\n        public static void CopyTo<TColor>(this TColor[,] source, TColor[,] destination, Gray<byte>[,] mask)\n            where TColor: unmanaged\n        {\n            if (source.Size() != mask.Size() || source.Size() != destination.Size())\n                throw new Exception(\"Image, mask, destination image must have the same size.\");\n\n            ParallelLauncher.Launch((thread) =>\n            {\n                if (mask[thread.Y, thread.X] != 0)\n                    destination[thread.Y, thread.X] = source[thread.Y, thread.X];\n            },\n            source.Width(), source.Height());\n        }\n\n        /// <summary>\n        /// Copies only those values from source to destination image area at which destination mask is true.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"source\">Source.</param>\n        /// <param name=\"sourceArea\">Source area.</param>\n        /// <param name=\"destination\">Destination.</param>\n        /// <param name=\"destinationOffset\">Destination location.</param>\n        /// <param name=\"destinationMask\">Destination mask.</param>\n        public static void CopySelective<T>(this T[,] source, Rectangle sourceArea, T[,] destination, Point destinationOffset, bool[,] destinationMask)\n        {\n            if(source.Size() != destinationMask.Size() || source.Size() != destination.Size())\n                throw new Exception(\"Image, mask, destination image must have the same size.\");\n\n            ParallelLauncher.Launch((thread) =>\n            {\n                if (destinationMask[destinationOffset.Y + thread.Y, destinationOffset.X + thread.X])\n                    destination[destinationOffset.Y + thread.Y, destinationOffset.X + thread.X] = source[sourceArea.Y + thread.Y, sourceArea.X + thread.X];\n            },\n            sourceArea.Width, sourceArea.Height);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Extensions/ImageFlipping.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Flip image direction. \n    /// They can be used as bit flags.\n    /// </summary>\n    [Flags]\n    public enum FlipDirection\n    {\n        /// <summary>\n        /// No flipping.\n        /// </summary>\n        None = 0x0,\n        /// <summary>\n        /// Horizontal flipping.\n        /// </summary>\n        Horizontal = 0x1,\n        /// <summary>\n        /// Vertical flipping\n        /// </summary>\n        Vertical = 0x2,\n        /// <summary>\n        /// All flipping (horizontal + vertical).\n        /// </summary>\n        All = 0x3\n    }\n\n    /// <summary>\n    /// Contains extension methods for image flipping.\n    /// </summary>\n    public static class ImageFlipping\n    {\n        /// <summary>\n        /// Flips an input image horizontally / vertically / both directions / or none (data copy).\n        /// </summary>\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\n        /// <param name=\"source\">Input image.</param>\n        /// <param name=\"flipDirection\">Flip direction.</param>\n        /// <returns>Returns flipped image.</returns>\n        public static TColor[,] FlipImage<TColor>(this TColor[,] source, FlipDirection flipDirection)\n            where TColor: unmanaged\n        {\n            TColor[,] dest = source.CopyBlank();\n            var sourceArea = new Rectangle(0, 0, source.Width(), source.Height());\n            var destinationOffset = new Point();\n            source.FlipImage(sourceArea, dest, destinationOffset, flipDirection);\n\n            return dest;\n        }\n\n        /// <summary>\n        /// Flips an input image horizontally / vertically / both directions / or none (data copy).\n        /// </summary>\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\n        /// <param name=\"source\">Input image.</param>\n        /// <param name=\"sourceArea\">Source area.</param>\n        /// <param name=\"destination\">Destination image.</param>\n        /// <param name=\"destinationOffset\">Destination image offset.</param>\n        /// <param name=\"flipDirection\">Flip direction.</param>\n        public static void FlipImage<TColor>(this TColor[,] source, Rectangle sourceArea, TColor[,] destination, Point destinationOffset, FlipDirection flipDirection)\n        {\n            int startDstRow = 0; int vDirection = 1;\n            int startDstCol = 0; int hDirection = 1;\n\n            if ((flipDirection & FlipDirection.Vertical) != 0)\n            {\n                startDstRow = (destinationOffset.Y + sourceArea.Height) - 1; vDirection = -1;\n            }\n            if ((flipDirection & FlipDirection.Horizontal) != 0)\n            {\n                startDstCol = (destinationOffset.X + sourceArea.Width) - 1; hDirection = -1;\n            }\n\n            for (int srcRow = 0, dstRow = startDstRow; srcRow < sourceArea.Bottom; srcRow++, dstRow += vDirection)\n            {\n                for (int srcCol = 0, dstCol = startDstCol; srcCol < sourceArea.Right; srcCol++, dstCol += hDirection)\n                {\n                    destination[dstRow, dstCol] = source[srcRow, srcCol];\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Extensions/SpatialConvolution.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides extension methods for the image spatial convolution.\n    /// </summary>\n    public static class SpatialConvolution\n    {\n        /*private unsafe static void convolve(KernelThread thread, float[,] source, float[,] kernel, float[,] destination)\n        {\n            int kernelWidth = kernel.Width();\n            int kernelHeight = kernel.Height();\n\n            var sum = 0f;\n            for (int r = 0; r < kernelHeight; r++)\n            {\n                for (int c = 0; c < kernelWidth; c++)\n                {\n                    sum += source[thread.Y + r, thread.X + c] * kernel[r, c];\n                }\n            }\n\n            destination[thread.Y + kernelHeight / 2, thread.X + kernelWidth / 2] = sum;\n        }*/\n\n        private unsafe static void convolve(KernelThread thread, float* source, int sourceStride, int channelCount,\n                                                                 float* kernel, int kernelWidth, int kernelHeight,\n                                                                 float* destination, int destinationStride)\n        {\n            source = (float*)((byte*)source + sourceStride * thread.Y) + thread.X;\n            destination = (float*)((byte*)destination + destinationStride * (thread.Y + kernelHeight / 2)) + (thread.X + kernelWidth / 2);\n\n            for (int ch = 0; ch < channelCount; ch++)\n            {\n                var srcPtr = source + ch;\n                var krnlPtr = kernel;\n\n                var sum = 0f;\n                for (int r = 0; r < kernelHeight; r++)\n                {\n                    for (int c = 0, srcCol = 0; c < kernelWidth; c++, srcCol += channelCount)\n                    {\n                        sum += srcPtr[srcCol] * krnlPtr[c];\n                    }\n\n                    srcPtr = (float*)((byte*)srcPtr + sourceStride);\n                    krnlPtr += kernelWidth;\n                }\n\n                destination[ch] = sum;\n            }\n        }\n\n        /// <summary>\n        /// Convolves the source image with the specified kernel.\n        /// </summary>\n        /// <param name=\"source\">Source data pointer.</param>\n        /// <param name=\"sourceWidth\">Source width.</param>\n        /// <param name=\"sourceHeight\">Source height.</param>\n        /// <param name=\"sourceStride\">Source stride.</param>\n        /// <param name=\"channelCount\">Source channel count.</param>\n        /// <param name=\"kernel\">Kernel pointer.</param>\n        /// <param name=\"kernelWidth\">Kernel width.</param>\n        /// <param name=\"kernelHeight\">Kernel height.</param>\n        /// <param name=\"destination\">Destination pointer.</param>\n        /// <param name=\"destinationStride\">Destination stride.</param>\n        public unsafe static void ConvolveUnsafe(float* source, int sourceWidth, int sourceHeight, int sourceStride, int channelCount,\n                                                 float* kernel, int kernelWidth, int kernelHeight,\n                                                 float* destination, int destinationStride)\n        {\n           ParallelLauncher.Launch(thread =>\n            {\n                convolve(thread, source, sourceStride, channelCount,\n                                 kernel, kernelWidth, kernelHeight,\n                                 destination, destinationStride);\n            },\n            sourceWidth - kernelWidth, sourceHeight - kernelHeight);\n        }\n\n        /// <summary>\n        /// Convolves the source image with the specified kernel.\n        /// </summary>\n        /// <param name=\"source\">Source image.</param>\n        /// <param name=\"kernel\">Kernel.</param>\n        /// <param name=\"area\">Working area.</param>\n        /// <returns>Convolved image.</returns>\n        public unsafe static float[,] Convolve(this float[,] source, float[,] kernel, Rectangle area)\n        {\n            var destination = new float[area.Height, area.Width];\n\n            fixed (float* srcPtr = &source[area.Y, area.X], kernelPtr = kernel, dstPtr = destination)\n            {\n                ConvolveUnsafe(srcPtr, area.Width, area.Height, source.Width() * sizeof(float), 1,\n                         kernelPtr, kernel.Width(), kernel.Height(),\n                         dstPtr, destination.Width() * sizeof(float));\n            }\n\n            return destination;\n        }\n\n        /// <summary>\n        /// Convolves the source image with the specified kernel.\n        /// </summary>\n        /// <param name=\"source\">Source image.</param>\n        /// <param name=\"kernel\">Kernel.</param>\n        /// <returns>Convolved image.</returns>\n        public unsafe static float[,] Convolve(this float[,] source, float[,] kernel)\n        {\n            var area = new Rectangle(0, 0, source.Width(), source.Height());\n            return source.Convolve(kernel, area);\n        }\n\n        /// <summary>\n        /// Convolves the source image with the specified kernel.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Color type.</typeparam>\n        /// <param name=\"source\">Source image.</param>\n        /// <param name=\"kernel\">Kernel.</param>\n        /// <returns>Convolved image.</returns>\n        public unsafe static TColor[,] Convolve<TColor>(this TColor[,] source, float[,] kernel)\n            where TColor: unmanaged, IColor<float>\n        {\n            var channelCount = source.ColorInfo().ChannelCount;\n            var destination = source.CopyBlank();\n\n            using (var srcImg = source.Lock())\n            using(var dstImg = destination.Lock())\n            {\n                fixed(float* kernelPtr = kernel)\n                {\n                    ConvolveUnsafe((float*)srcImg.ImageData, srcImg.Width, srcImg.Height, srcImg.Stride, channelCount,\n                                   kernelPtr, kernel.Width(), kernel.Height(), \n                                   (float*)dstImg.ImageData, dstImg.Stride);\n                }          \n            }\n\n            return destination;\n        }\n\n    }\n}\n"
  },
  {
    "path": "Source/Image/Image.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <AssemblyName>DotImaging.Image</AssemblyName>\n    <RootNamespace>DotImaging</RootNamespace>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <Platforms>AnyCPU</Platforms>\n  </PropertyGroup> \n\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <DocumentationFile>bin\\DotImaging.Image.xml</DocumentationFile>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Drawing.Primitives\" Version=\"4.3.0\" />\n  </ItemGroup>\n\n  <!-- NuGet -->\n  <PropertyGroup>\n    <Version>5.3.0</Version>\n\n    <PackageId>DotImaging.Image</PackageId>\n    <Description>.NET image array extensions. Color and depth conversions. Slim unmanaged structure for fast pixel manipulation. LINQ on 2D arrays.</Description>\n    <PackageTags>image, managed-image, array-image, 2D LINQ</PackageTags>\n\n    <Authors>Darko Jurić</Authors>\n    <Copyright>Darko Jurić</Copyright>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt</PackageLicenseUrl>\n    <PackageIconUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png</PackageIconUrl>\n    <PackageProjectUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</PackageProjectUrl>\n    <RepositoryUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</RepositoryUrl>\n\n    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    <PackageOutputPath>../../Deploy/NuGet/bin/</PackageOutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\".nuSpec/readmeImage.txt\">\n      <PackagePath>Readme.txt</PackagePath>\n    </Content>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/Image/Interop/CvMat.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// OpenCV's Mat structure\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public unsafe struct CvMat\n    {\n        /// <summary>\n        /// OpenCV's channel depth enumeration.\n        /// </summary>\n        public enum CvChannelDepth : int\n        {\n            /// <summary>\n            /// 8-bit unsigned type.\n            /// </summary>\n            CV_8U = 0,\n            /// <summary>\n            /// 8-bit signed type.\n            /// </summary>\n            CV_8S = 1,\n            /// <summary>\n            /// 16-bit unsigned type.\n            /// </summary>\n            CV_16U = 2,\n            /// <summary>\n            /// 16-bit signed type.\n            /// </summary>\n            CV_16S = 3,\n            /// <summary>\n            /// 32-bit integer signed type.\n            /// </summary>\n            CV_32S = 4,\n            /// <summary>\n            /// 32-bit floating-point signed type.\n            /// </summary>\n            CV_32F = 5,\n            /// <summary>\n            /// 64-bit floating-point signed type.\n            /// </summary>\n            CV_64F = 6,\n            /// <summary>\n            /// User defined type.\n            /// </summary>\n            UserType = 7\n        }\n\n        const int CV_CN_SHIFT = 3;\n\n        /// <summary>\n        /// Encoded mat depth and number of channels.\n        /// </summary>\n        int matType;\n        /// <summary>\n        /// Number of bytes per image row.\n        /// </summary>\n        public int Step;\n\n        //internal\n        int* refCount;\n        int hdr_refcount;\n\n        /// <summary>\n        /// Image data pointer.\n        /// </summary>\n        public IntPtr ImageData;\n        /// <summary>\n        /// Image height.\n        /// </summary>\n        public int Height;\n        /// <summary>\n        /// Image width.\n        /// </summary>\n        public int Width;\n\n        /// <summary>\n        /// Creates new CvMat from the already existing data.\n        /// </summary>\n        /// <param name=\"imageData\">Image data pointer.</param>\n        /// <param name=\"width\">Image width.</param>\n        /// <param name=\"height\">Image height.</param>\n        /// <param name=\"stride\">Number of bytes per row.</param>\n        /// <param name=\"depthType\">Channel depth.</param>\n        /// <param name=\"channelCount\">Channel count.</param>\n        /// <returns></returns>\n        public static CvMat FromUserData(IntPtr imageData, int width, int height, int stride, CvChannelDepth depthType, int channelCount)\n        {\n            //taken from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/types_c.h\n            const int CV_MAT_MAGIC_VAL = 0x42420000;\n\n            //CV_MAKETYPE from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h\n            const int CV_MAT_CONT_FLAG_SHIFT = 14;\n            const int CV_MAT_CONT_FLAG = (1 << CV_MAT_CONT_FLAG_SHIFT);\n\n            //CV_MAKETYPE from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h\n            var matDepth = getDepth((int)depthType);\n            var cvType = matDepth + ((channelCount - 1) << CV_CN_SHIFT);\n            var mType = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | cvType;\n\n            return new CvMat\n            {\n                ImageData = imageData,\n                Width = width,\n                Height = height,\n                Step = stride,\n                matType = mType,\n                hdr_refcount = 0,\n                refCount = null\n            };\n        }\n\n        /// <summary>\n        /// Gets the channel depth.\n        /// </summary>\n        public CvChannelDepth ChannelDepth\n        {\n            get { return (CvChannelDepth)getDepth(matType); }\n        }\n\n        /// <summary>\n        /// Gets the channel count.\n        /// </summary>\n        public int ChannelCount\n        {\n            get\n            {\n                //CV_ELEM_SIZE from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h\n                //0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem))\n                const int CV_CN_MAX = 512;\n                const int CV_MAT_CN_MASK = ((CV_CN_MAX - 1) << CV_CN_SHIFT);\n\n                var CV_MAT_CN = (((matType & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1);\n                return (CV_MAT_CN << ((((sizeof(int) / 4 + 1) * 16384 | 0x3a50) >> getDepth(matType) * 2) & 3));\n            }\n        }\n\n        //CV_MATDEPTH from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h\n        static int getDepth(int flags)\n        {\n            const int CV_DEPTH_MAX = (1 << CV_CN_SHIFT);\n            const int CV_MAT_DEPTH_MASK = (CV_DEPTH_MAX - 1);\n\n            return (flags & CV_MAT_DEPTH_MASK);\n        }\n    }\n\n    /// <summary>\n    /// Provides extension CvMat conversion methods\n    /// </summary>\n    public static class CvMatTypeConversions\n    {\n        static Dictionary<Type, CvMat.CvChannelDepth> typeConversion = null;\n\n        static CvMatTypeConversions()\n        {\n            typeConversion = new Dictionary<Type, CvMat.CvChannelDepth>();\n\n            typeConversion.Add(typeof(byte), CvMat.CvChannelDepth.CV_8U);\n            typeConversion.Add(typeof(sbyte), CvMat.CvChannelDepth.CV_8S);\n\n            typeConversion.Add(typeof(ushort), CvMat.CvChannelDepth.CV_16U);\n            typeConversion.Add(typeof(short), CvMat.CvChannelDepth.CV_16S);\n\n            typeConversion.Add(typeof(int), CvMat.CvChannelDepth.CV_32S);\n\n            typeConversion.Add(typeof(float), CvMat.CvChannelDepth.CV_32F);\n            typeConversion.Add(typeof(double), CvMat.CvChannelDepth.CV_64F);\n        }\n\n        /// <summary>\n        /// Represents the existing image as CvMat structure where data is shared.\n        /// </summary>\n        /// <param name=\"image\">Image.</param>\n        /// <returns>CvMat representation.</returns>\n        public static CvMat AsCvMat(this IImage image)\n        {\n            var depthType = typeConversion[image.ColorInfo.ChannelType];\n\n            return CvMat.FromUserData(image.ImageData, image.Width, image.Height, image.Stride, depthType, image.ColorInfo.ChannelCount);\n        }\n\n        /// <summary>\n        /// Copies data to managed array.\n        /// </summary>\n        /// <typeparam name=\"TColor\">Pixel color type.</typeparam>\n        /// <param name=\"cvMat\">OpenCV matrix.</param>\n        /// <returns>Managed image representation.</returns>\n        public static TColor[,] ToArray<TColor>(this CvMat cvMat)\n            where TColor: unmanaged, IColor\n        {\n            var im = new TColor[cvMat.Height, cvMat.Width];\n\n            using (var uIm = Image<TColor>.Lock(im))\n            {\n                Copy.UnsafeCopy2D(cvMat.ImageData, uIm.ImageData, cvMat.Step, uIm.Stride, uIm.Height);\n            }\n\n            return im;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Interop/IplImage.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Represents the OpenCV's IplImage structure which enables OpenCV / EmguCV interoperability.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]\n    public unsafe struct IplImage\n    {\n        /// <summary>\n        /// Constant for signed data types.\n        /// </summary>\n        public const uint IPL_DEPTH_SIGN = 0x80000000;\n\n        /// <summary>\n        /// Depth constants for IplImage channels.\n        /// </summary>\n        public enum IplChannelDepth : uint\n        {\n            /// <summary>\n            /// Unsigned 1bit\n            /// </summary>\n            IPL_DEPTH_1U = 1,\n            /// <summary>\n            /// Unsigned 8-bit integer\n            /// </summary>\n            IPL_DEPTH_8U = 8,\n            /// <summary>\n            /// Signed 8-bit integer\n            /// </summary>\n            IPL_DEPTH_8S = (IPL_DEPTH_SIGN | 8),\n            /// <summary>\n            /// Unsigned 16-bit integer\n            /// </summary>\n            IPL_DEPTH_16U = 16,\n            /// <summary>\n            /// Signed 16-bit integer\n            /// </summary>\n            IPL_DEPTH_16S = (IPL_DEPTH_SIGN | 16),\n            /// <summary>\n            /// Signed 32-bit integer.\n            /// </summary>\n            IPL_DEPTH_32S = (IPL_DEPTH_SIGN | 32),\n            /// <summary>\n            /// Single-precision floating point\n            /// </summary>\n            IPL_DEPTH_32F = 32,\n            /// <summary>\n            /// Double-precision floating point\n            /// </summary>\n            IPL_DEPTH_64F = 64\n        }\n\n        /// <summary>\n        /// IplImage channel data order.\n        /// </summary>\n        public enum ChannelDataOrder : int\n        {\n            /// <summary>\n            /// Interleaved color channels.\n            /// </summary>\n            INTERLEAVED = 0,\n            /// <summary>\n            /// Separate color channels. (CreateImage only creates images with interleaved channels.)\n            /// </summary>\n            SEPARATE = 1\n        }\n\n        /// <summary>\n        /// IplImage data origin.\n        /// </summary>\n        public enum DataOrigin : int\n        {\n            /// <summary>\n            /// Data origin is located in the top-left corner.\n            /// </summary>\n            TopLeft = 0,\n            /// <summary>\n            /// Data origin is located in the bottom-left corner (Windows bitmap).\n            /// </summary>\n            BottomLeft = 1\n        }\n\n        /// <summary>\n        /// Size of the structure\n        /// </summary>\n        public int StructureSize;\n        /// <summary>\n        /// Version, always equal 0\n        /// </summary>\n        public int ID;\n        /// <summary>\n        /// Number of channels. Most OpenCV functions support 1-4 channels.\n        /// </summary>\n        public int NumberOfChannels;\n        /// <summary>\n        /// Ignored by OpenCV (set to zero).\n        /// </summary>\n        public int AlphaChannel;\n        /// <summary>\n        /// Channel depth in bits + the optional sign bit\n        /// </summary>\n        public IplChannelDepth ChannelDepth;\n        /// <summary>\n        /// Ignored by OpenCV. The OpenCV function CvtColor requires the source and destination color spaces as parameters.\n        /// </summary>\n        public fixed byte ColorModel[4];\n        /// <summary>\n        /// Ignored by OpenCV\n        /// </summary>\n        public fixed byte ChannelSeq[4];\n        /// <summary>\n        /// Interleaved or separate (not used) channel order.\n        /// </summary>\n        public ChannelDataOrder DataOrder;\n        /// <summary>\n        /// Data origin: top-left or bottom-right (not used).\n        /// </summary>\n        public DataOrigin Origin;\n        /// <summary>\n        /// Alignment of image rows (4 or 8). (Ignored by OpenCV)\n        /// </summary>\n        public int Align;\n        /// <summary>\n        /// Image width\n        /// </summary>\n        public int Width;\n        /// <summary>\n        /// Image height\n        /// </summary>\n        public int Height;\n        /// <summary>\n        /// Region Of Interest (ROI). If not NULL, only this image region will be processed.\n        /// It is always null if generic image is represented as OpenCV image.\n        /// </summary>\n        public IntPtr ROI;\n        /// <summary>\n        /// Must be NULL in OpenCV.\n        /// </summary>\n        public IntPtr MaskROI;\n        /// <summary>\n        /// Must be NULL in OpenCV.\n        /// </summary>\n        public IntPtr ImageId;\n        /// <summary>\n        /// Must be NULL in OpenCV.\n        /// </summary>\n        public IntPtr TileInfo;\n        /// <summary>\n        /// Image data size in bytes.\n        /// </summary>\n        public int ImageSize;\n        /// <summary>\n        /// A pointer to the aligned image data.\n        /// </summary>\n        public IntPtr ImageData;\n        /// <summary>\n        /// The size of an aligned image row, in bytes.\n        /// </summary>\n        public int WidthStep;\n        /// <summary>\n        /// Border completion mode, ignored by OpenCV.\n        /// </summary>\n        public fixed int BorderMode[4];\n        /// <summary>\n        /// Border completion mode, ignored by OpenCV.\n        /// </summary>\n        public fixed int BorderConst[4];\n        /// <summary>\n        /// A pointer to the origin of the image data (not necessarily aligned). This is used for image deallocation.\n        /// During casting between generic image to OpenCV image it is set to null.\n        /// </summary>\n        public IntPtr ImageDataOrigin;\n\n        internal IplImage(IImage image, Func<Type, IplChannelDepth> translationFunc)\n        {\n            /************************ default values initialization *********************************/\n            this.StructureSize = sizeof(IplImage);\n            this.ID = 0;\n            this.Align = 4;\n            this.AlphaChannel = 0;\n            this.DataOrder = ChannelDataOrder.INTERLEAVED;\n            this.Origin = DataOrigin.TopLeft;\n            this.ROI = IntPtr.Zero;\n            this.MaskROI = IntPtr.Zero;\n            this.ImageId = IntPtr.Zero;\n            this.TileInfo = IntPtr.Zero;\n            this.ImageDataOrigin = IntPtr.Zero; //set to zero to avoid deallocation (should be equal to ImageData)\n            /************************ default values initialization *********************************/\n\n            var colorInfo = image.ColorInfo;\n\n            this.Align = (image.Stride % 8 == 0) ? 8 :\n                         (image.Stride % 4 == 0) ? 4 : 0; //TODO: check does OpenCV supports non-aligned images\n\n            this.ChannelDepth = translationFunc(colorInfo.ColorType);\n            this.NumberOfChannels = colorInfo.ChannelCount;\n\n            this.Width = image.Width;\n            this.Height = image.Height;\n            this.WidthStep = image.Stride;\n            this.ImageSize = image.Stride * image.Height;\n\n            this.ImageData = image.ImageData;\n\n        }\n\n        /// <summary>\n        /// Converts a pointer to an IplImage structure.\n        /// </summary>\n        /// <param name=\"pointerToStructure\"></param>\n        /// <returns></returns>\n        public static IplImage FromPointer(IntPtr pointerToStructure)\n        {\n            if (pointerToStructure.Equals(IntPtr.Zero))\n                return default(IplImage);\n\n            return (IplImage)Marshal.PtrToStructure(pointerToStructure, typeof(IplImage));\n        }\n    }\n\n    /// <summary>\n    /// Contains methods for casting an generic image to an IplImage.\n    /// </summary>\n    public static class ImageOpenCVImageConversions\n    {\n        class IplColorInfo: IEquatable<IplColorInfo>\n        {\n            public IplColorInfo(int channelCount, IplImage.IplChannelDepth channelDepth)\n            {\n                this.ChannelCount = channelCount;\n                this.ChannelDepth = channelDepth;\n            }\n\n            public int ChannelCount { get; private set; }\n            public IplImage.IplChannelDepth ChannelDepth { get; private set; }\n\n            public bool Equals(IplColorInfo other)\n            {\n                if (other.ChannelCount == this.ChannelCount &&\n                    other.ChannelDepth == this.ChannelDepth)\n                    return true;\n\n                return false;\n            }\n\n            public override int GetHashCode()\n            {\n                return this.ChannelCount ^ (int)this.ChannelDepth;\n            }\n        }\n\n        class GenericImageConstructor\n        {\n            public static GenericImageConstructor Create<TColor>()\n                where TColor: unmanaged, IColor\n            {\n                GenericImageConstructor ctor = new GenericImageConstructor();\n                ctor.ColorType = typeof(TColor);\n\n                ctor.ToImage = (iplImage, destructor) =>\n                {\n                    if (destructor != null)\n                        return new Image<TColor>(iplImage.ImageData, iplImage.Width, iplImage.Height, iplImage.WidthStep, iplImage, destructor);\n                    else\n                        return new Image<TColor>(iplImage.ImageData, iplImage.Width, iplImage.Height, iplImage.WidthStep, iplImage);\n                };\n\n                return ctor;\n            }\n\n            public Type ColorType { get; private set; }\n\n            public Func<IplImage, Action<object>, IImage> ToImage { get; private set; }\n\n            private GenericImageConstructor()\n            { }\n        }\n\n        static Dictionary<Type, IplColorInfo> colorAssociations;\n        static Dictionary<IplColorInfo, GenericImageConstructor> colorConstructorPairs;\n\n        static ImageOpenCVImageConversions()\n        {\n            colorAssociations = new Dictionary<Type, IplColorInfo>();\n\n            //Gray\n            colorAssociations.Add(typeof(Gray<sbyte>),  new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8S));\n            colorAssociations.Add(typeof(Gray<byte>),   new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8U));\n            colorAssociations.Add(typeof(Gray<short>),  new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16S));\n            colorAssociations.Add(typeof(Gray<ushort>), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16U));\n            colorAssociations.Add(typeof(Gray<int>),    new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32S));\n            colorAssociations.Add(typeof(Gray<float>),  new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32F));\n            colorAssociations.Add(typeof(Gray<double>), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_64F));\n\n            //Color2 - TODO ??\n\n            //Bgr\n            colorAssociations.Add(typeof(Bgr<sbyte>), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8S));\n            colorAssociations.Add(typeof(Bgr<byte>), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8U));\n            colorAssociations.Add(typeof(Bgr<short>), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16S));\n            colorAssociations.Add(typeof(Bgr<ushort>), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16U));\n            colorAssociations.Add(typeof(Bgr<int>), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32S));\n            colorAssociations.Add(typeof(Bgr<float>), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32F));\n            colorAssociations.Add(typeof(Bgr<double>), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_64F));\n\n            //Bgra\n            colorAssociations.Add(typeof(Bgra<sbyte>), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8S));\n            colorAssociations.Add(typeof(Bgra<byte>), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8U));\n            colorAssociations.Add(typeof(Bgra<short>), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16S));\n            colorAssociations.Add(typeof(Bgra<ushort>), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16U));\n            colorAssociations.Add(typeof(Bgra<int>), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32S));\n            colorAssociations.Add(typeof(Bgra<float>), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32F));\n            colorAssociations.Add(typeof(Bgra<double>), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_64F));\n            /****************************************************************************************/\n\n\n            colorConstructorPairs = new Dictionary<IplColorInfo, GenericImageConstructor>();\n\n            //Gray\n            colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8S), GenericImageConstructor.Create<Gray<sbyte>>());\n            colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8U), GenericImageConstructor.Create<Gray<byte>>());\n            colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16S), GenericImageConstructor.Create<Gray<short>>());\n            colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16U), GenericImageConstructor.Create<Gray<ushort>>());\n            colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32S), GenericImageConstructor.Create<Gray<int>>());\n            colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32F), GenericImageConstructor.Create<Gray<float>>());\n            colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_64F), GenericImageConstructor.Create<Gray<double>>());\n\n            //Color2 - TODO\n\n            //Bgr\n            colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8S), GenericImageConstructor.Create<Bgr<sbyte>>());\n            colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8U), GenericImageConstructor.Create<Bgr<byte>>());\n            colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16S), GenericImageConstructor.Create<Bgr<short>>());\n            colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16U), GenericImageConstructor.Create<Bgr<ushort>>());\n            colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32S), GenericImageConstructor.Create<Bgr<int>>());\n            colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32F), GenericImageConstructor.Create<Bgr<float>>());\n            colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_64F), GenericImageConstructor.Create<Bgr<double>>());\n\n            //Bgra\n            colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8S), GenericImageConstructor.Create<Bgra<sbyte>>());\n            colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8U), GenericImageConstructor.Create<Bgra<byte>>());\n            colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16S), GenericImageConstructor.Create<Bgra<short>>());\n            colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16U), GenericImageConstructor.Create<Bgra<ushort>>());\n            colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32S), GenericImageConstructor.Create<Bgra<int>>());\n            colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32F), GenericImageConstructor.Create<Bgra<float>>());\n            colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_64F), GenericImageConstructor.Create<Bgra<double>>());\n        }\n\n        /// <summary>\n        /// Casts an image to OpeCV image (IplImage). No data copy is involved.\n        /// </summary>\n        /// <param name=\"image\">Generic image.</param>\n        /// <returns>OpeCV image format.</returns>\n        public static IplImage AsCvIplImage(this IImage image)\n        {\n            return new IplImage(image, (channelType) =>\n            {\n                /*if (image.IsOpenCVCompatibile() == false)\n                    throw new Exception(\"The image stride must be compatible to OpenCV image stride!\");*/\n\n                IplColorInfo iplColorInfo;\n                bool exist = colorAssociations.TryGetValue(channelType, out iplColorInfo);\n\n                if (!exist)\n                    throw new Exception(\"The image can not be casted to IplImage because the image depth type is not supported by OpenCV!\");\n\n                return iplColorInfo.ChannelDepth;\n            });\n        }\n\n        /// <summary>\n        /// Casts iplImage in generic image representation.\n        /// </summary>\n        /// <param name=\"iplImage\">IplImage structure.</param>\n        /// <param name=\"destructor\">Destructor which is called when created generic image is disposed.</param>\n        /// <returns>Image.</returns>\n        public static unsafe IImage AsImage(this IplImage iplImage, Action<object> destructor = null)\n        {\n            if (iplImage.Equals(default(IplImage)))\n                return null;\n\n            var imgCtorInfo = colorConstructorPairs[new IplColorInfo(iplImage.NumberOfChannels, iplImage.ChannelDepth)];\n            return imgCtorInfo.ToImage(iplImage, destructor);    \n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Linq/ImagingLinq.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace DotImaging.Linq\n{\n    /// <summary>\n    /// Contains 2D array Linq extensions\n    /// </summary>\n    public static partial class ImageLinqExtensions\n    {\n        /// <summary>\n        /// Converts the specified collection to a 2D array determined by the specified size.\n        /// <para>The number of elements must match the number of elements in the collection.</para>\n        /// </summary>\n        /// <typeparam name=\"T\">Element type</typeparam>\n        /// <param name=\"collection\">Collection</param>\n        /// <param name=\"size\">Array size</param>\n        /// <returns>2D array</returns>\n        public static T[,] ToArray2D<T>(this IEnumerable<T> collection, Size size)\n        {\n            return collection.ToArray2D(size.Width, size.Height);\n        }\n\n        /// <summary>\n        /// Converts the specified collection to a 2D array determined by the specified size.\n        /// <para>The number of elements must match the number of elements in the collection.</para>\n        /// </summary>\n        /// <typeparam name=\"T\">Element type</typeparam>\n        /// <param name=\"collection\">Collection</param>\n        /// <param name=\"width\">Array width</param>\n        /// <param name=\"height\">Array height</param>\n        /// <returns>2D array</returns>\n        public static T[,] ToArray2D<T>(this IEnumerable<T> collection, int width, int height)\n        {\n            T[,] dest = new T[height, width];\n\n            int row = 0, col = 0;\n            foreach (var item in collection)\n            {\n                dest[row, col] = item;\n\n                col++;\n                if (col >= width)\n                {\n                    col = 0;\n                    row++;\n                }\n            }\n\n            return dest;\n        }\n\n        /// <summary>\n        /// Gets the 2x CPU number of slices which width is equal to array width.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type</typeparam>\n        /// <param name=\"array\">Array</param>\n        /// <returns>Array slices</returns>\n        public static IEnumerable<Slice2D<T>> SliceUniform<T>(this T[,] array)\n        {\n            int sliceCount = Environment.ProcessorCount * 2;\n            int sliceHeight = array.Height() / sliceCount;\n\n            int y = 0;\n            Rectangle area = Rectangle.Empty;\n\n            for (int sliceIdx = 0; sliceIdx < (sliceCount - 1); sliceIdx++)\n            {\n                area = new Rectangle(0, y, array.Width(), sliceHeight);\n                y += sliceHeight;\n\n                yield return new Slice2D<T>(array, area);\n            }\n\n            //last slice\n            area = new Rectangle(0, y, array.Width(), array.Height() - y);\n            yield return new Slice2D<T>(array, area);\n        }\n\n        /// <summary>\n        /// Creates a parallel-ordered query of the array element collection.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type</typeparam>\n        /// <param name=\"array\">Array</param>\n        /// <returns>Parallel-ordered query</returns>\n        public static ParallelQuery<T> AsParallelOrdered<T>(this T[,] array) //slow\n        {\n            //return array.AsGrid().AsParallel().SelectMany(x => x.Array.AsEnumerable(x.Area));\n            return array.AsEnumerable().AsParallel().AsOrdered();\n        }\n\n        /// <summary>\n        /// Represents the specified array row as enumerable collection.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type</typeparam>\n        /// <param name=\"array\">Array</param>\n        /// <param name=\"row\">Row index</param>\n        /// <returns>Row elements</returns>\n        public static IEnumerable<T> Row<T>(this T[,] array, int row)\n        {\n            var width = array.Width();\n\n            for (int col = 0; col < width; col++)\n            {\n                yield return array[row, col];\n            }\n        }\n\n        /// <summary>\n        /// Represents the specified array column as enumerable collection.\n        /// </summary>\n        /// <typeparam name=\"T\">Element type</typeparam>\n        /// <param name=\"array\">Array</param>\n        /// <param name=\"column\">Column index</param>\n        /// <returns>Column elements</returns>\n        public static IEnumerable<T> Column<T>(this T[,] array, int column)\n        {\n            var height = array.Height();\n\n            for (int row = 0; row < height; row++)\n            {\n                yield return array[row, column];\n            }\n        }\n\n        /// <summary>\n        /// Represents the specified array portion as enumerable collection.\n        /// <para>The scan path is from top-left -> bottom-right border.</para>\n        /// </summary>\n        /// <typeparam name=\"T\">Element type</typeparam>\n        /// <param name=\"array\">Array</param>\n        /// <param name=\"area\">Array portion</param>\n        /// <returns>Element collection</returns>\n        public static IEnumerable<T> AsEnumerable<T>(this T[,] array, Rectangle area)\n        {\n            for (int row = area.Top; row < area.Bottom; row++)\n            {\n                for (int col = area.Left; col < area.Right; col++)\n                {\n                    yield return array[row, col];\n                }\n            }\n        }\n\n        /// <summary>\n        /// Represents the specified array as enumerable collection.\n        /// <para>The scan path is from top-left -> bottom-right border.</para>\n        /// </summary>\n        /// <typeparam name=\"T\">Element type.</typeparam>\n        /// <param name=\"array\">Array</param>\n        /// <returns>Element collection</returns>\n        public static IEnumerable<T> AsEnumerable<T>(this T[,] array)\n        {\n            var area = new Rectangle(0, 0, array.Width(), array.Height());\n            return array.AsEnumerable(area);\n        }\n\n        /// <summary>\n        /// Enumerates both arrays simultaneously and executes user-specified function.\n        /// <para>The scan path is from top-left -> bottom-right border.</para>\n        /// </summary>\n        /// <typeparam name=\"TFirst\">First data type.</typeparam>\n        /// <typeparam name=\"TSecond\">Second data type.</typeparam>\n        /// <typeparam name=\"TOutput\">Output type.</typeparam>\n        /// <param name=\"first\">First array.</param>\n        /// <param name=\"second\">Second array.</param>\n        /// <param name=\"function\">User specified function.</param>\n        /// <param name=\"area\">Working area</param>\n        /// <returns>The result collection which elements are generated by using user-specified function.</returns>\n        public static IEnumerable<TOutput> EnumerateWith<TFirst, TSecond, TOutput>(this TFirst[,] first, TSecond[,] second, Func<TFirst, TSecond, TOutput> function, Rectangle area)\n        {\n            if (first.Width() < area.Right || first.Height() < area.Bottom ||\n                second.Width() < area.Right || second.Height() < area.Bottom ||\n                area.Left < 0 || area.Top < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(area), \"The specified area must be witihin the images.\");\n            }\n\n            for (int row = area.Top; row < area.Bottom; row++)\n            {\n                for (int col = area.Left; col < area.Right; col++)\n                {\n                    yield return function(first[row, col], second[row, col]);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Enumerates both arrays simultaneously and executes user-specified function.\n        /// <para>The scan path is from top-left -> bottom-right border.</para>\n        /// </summary>\n        /// <typeparam name=\"TFirst\">First data type.</typeparam>\n        /// <typeparam name=\"TSecond\">Second data type.</typeparam>\n        /// <typeparam name=\"TOutput\">Output type.</typeparam>\n        /// <param name=\"first\">First array.</param>\n        /// <param name=\"second\">Second array.</param>\n        /// <param name=\"function\">User specified function.</param>\n        /// <returns>The result collection which elements are generated by using user-specified function.</returns>\n        public static IEnumerable<TOutput> EnumerateWith<TFirst, TSecond, TOutput>(this TFirst[,] first, TSecond[,] second, Func<TFirst, TSecond, TOutput> function)\n        {\n            if (first.Width() != second.Width() ||\n                first.Height() != second.Height())\n            {\n                throw new ArgumentException(\"Image sizes must be the same.\");\n            }\n\n            Rectangle area = new Rectangle(Point.Empty, first.Size());\n            return EnumerateWith(first, second, function, area);\n        }\n\n    }\n}\n"
  },
  {
    "path": "Source/Image/ParallelLauncher.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Runtime.CompilerServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Kernel thread structure which represents the working point.\n    /// </summary>\n    public struct KernelThread\n    {\n        /// <summary>\n        /// Horizontal offset.\n        /// </summary>\n        public int X;\n        /// <summary>\n        /// Vertical offset.\n        /// </summary>\n        public int Y;\n    }\n\n    /// <summary>\n    /// Provides a launch method and extension methods for parallel array processing.\n    /// </summary>\n    public static class ParallelLauncher\n    {      \n        /// <summary>\n        /// launches the specified kernel function in parallel.\n        /// </summary>\n        /// <typeparam name=\"T\">Array element type.</typeparam>\n        /// <param name=\"array\">Array.</param>\n        /// <param name=\"kernel\">Kernel function.</param>\n        /// <param name=\"gridX\">Horizontal grid size.</param>\n        /// <param name=\"gridY\">Vertical grid size</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Launch<T>(this T[,] array, Action<KernelThread, T[,]> kernel, int gridX, int gridY)\n        {\n            Launch(thread => \n            {\n                kernel(thread, array);\n            }, \n            gridX, gridY);\n        }\n\n        /// <summary>\n        /// Launches the specified kernel function in parallel.\n        /// </summary>\n        /// <param name=\"kernel\">Kernel function.</param>\n        /// <param name=\"gridX\">Horizontal grid size.</param>\n        /// <param name=\"gridY\">Vertical grid size</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Launch(Action<KernelThread> kernel, int gridX, int gridY)\n        {\n            System.Threading.Tasks.Parallel.For(0, gridY, (j) =>\n            {\n                KernelThread th = new KernelThread();\n\n                th.Y = j;\n                for (int i = 0; i < gridX; i++)\n                {\n                    th.X = i;\n                    kernel(th);\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Slice2D.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// A wrapper for 2D sub-array.\n    /// </summary>\n    /// <typeparam name=\"T\">Element type.</typeparam>\n    public class Slice2D<T>\n    {\n        /// <summary>\n        /// Creates a new grid from the specified array.\n        /// </summary>\n        /// <param name=\"array\">Array.</param>\n        public Slice2D(T[,] array)\n        {\n            this.Array = array;\n            this.Area = new Rectangle(0, 0, array.Width(), array.Height());\n        }\n\n        /// <summary>\n        /// Creates a new grid from the specified array.\n        /// </summary>\n        /// <param name=\"array\">Array.</param>\n        /// <param name=\"area\">Sub-array area.</param>\n        public Slice2D(T[,] array, Rectangle area)\n        {\n            this.Array = array;\n            this.Area = area;\n        }\n\n        /// <summary>\n        /// Gets the original array.\n        /// </summary>\n        public T[,] Array { get; private set; }\n\n        /// <summary>\n        /// Gets the working array area.\n        /// </summary>\n        public Rectangle Area { get; private set; }\n\n        /// <summary>\n        /// Gets or sets the specified value.\n        /// </summary>\n        /// <param name=\"y\">Offset from the upper-left y area location.</param>\n        /// <param name=\"x\">Offset from the upper-left x area location.</param>\n        /// <returns>Value.</returns>\n        public T this[int y, int x]\n        {\n            get { return Array[Area.Y + y, Area.X + x]; }\n            set { Array[Area.Y + y, Area.X + x] = value; }\n        }\n\n        /// <summary>\n        /// Converts the array into grid representation.\n        /// </summary>\n        /// <param name=\"array\">Array.</param>\n        /// <returns>Grid.</returns>\n        public static implicit operator Slice2D<T>(T[,] array)\n        {\n            return new Slice2D<T>(array);\n        }\n\n        /// <summary>\n        /// Determines whether the specified object is equal to the current object.\n        /// </summary>\n        /// <param name=\"other\">Other object</param>\n        /// <returns>True if two objects are equal, false otherwise.</returns>\n        public override bool Equals(object other)\n        {\n            var otherObj = other as Slice2D<T>;\n            if (otherObj == null)\n                return false;\n\n            if(this.Array.Equals(otherObj.Array) && this.Area.Equals(otherObj.Area))\n                return true;\n            else\n                return false;\n        }\n\n        /// <summary>\n        /// Serves as a hash function for a particular type.\n        /// </summary>\n        /// <returns>A hash code for the current object.</returns>\n        public override int GetHashCode()\n        {\n            return base.GetHashCode();\n        }\n    }\n\n    /// <summary>\n    /// Provides extensions for <see cref=\"Slice2D{T}\"/>.\n    /// </summary>\n    public static class Slice2DExtensions\n    {\n        /// <summary>\n        /// Clones the portion of the array defined by the provided slice.\n        /// </summary>\n        /// <typeparam name=\"T\">Value, blittable type.</typeparam>\n        /// <param name=\"slice\">Slice.</param>\n        /// <returns>Cloned portion of the array.</returns>\n        public static unsafe T[,] Clone<T>(this Slice2D<T> slice)\n            where T : unmanaged\n        {\n            T[,] patch = null;\n\n            using (var uSrc = slice.Array.Lock(slice.Area))\n            {\n                patch = uSrc.Clone();\n            }\n\n            return patch;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Image/Unmanaged/IImage.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Represents interface to the <see cref=\"Image&lt;TColor&gt;\"/> class.\n    /// </summary>\n    public interface IImage: IDisposable, IEquatable<IImage>\n    {\n        /// <summary>\n        /// Gets unmanaged image data.\n        /// </summary>\n        IntPtr ImageData { get; }\n        /// <summary>\n        /// Gets image width.\n        /// </summary>\n        int Width { get; }\n        /// <summary>\n        /// Gets image height.\n        /// </summary>\n        int Height { get; }\n        /// <summary>\n        /// Gets image stride.\n        /// </summary>\n        int Stride { get; }\n        /// <summary>\n        /// Gets image size.\n        /// </summary>\n        Size Size { get; }\n        /// <summary>\n        /// Gets image color info.\n        /// </summary>\n        ColorInfo ColorInfo { get; }\n        /// <summary>\n        /// Gets image data at specified location.\n        /// </summary>\n        /// <param name=\"row\">Row index.</param>\n        /// <param name=\"col\">Column index.</param>\n        /// <returns>Data pointer.</returns>\n        IntPtr GetData(int row, int col);\n        /// <summary>\n        /// Gets image data at specified location.\n        /// </summary>\n        /// <param name=\"row\">Row index.</param>\n        /// <returns>Data pointer.</returns>\n        IntPtr GetData(int row);\n        /// <summary>\n        /// Gets sub-image from specified area. Data is shared.\n        /// </summary>\n        /// <param name=\"rect\">Area of an image for sub-image creation.</param>\n        /// <returns>Sub-image.</returns>\n        IImage GetSubRect(Rectangle rect);\n    }\n}\n"
  },
  {
    "path": "Source/Image/Unmanaged/Image'1.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\nusing System;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Implements generic image type and provides a basic data manipulation. Other functions are built as extensions making the class light-weight and portable.\n    /// <para>Other extensions and satellite assemblies enables multiple interoperability with other libraries such as AForge.NET, OpenCV, EmguCV.</para>\n    /// </summary>\n    /// <typeparam name=\"TColor\">Color type. The structure must be blittable.</typeparam>\n    public class Image<TColor> : IImage, IEquatable<IImage>, IDisposable\n           where TColor: unmanaged\n    {\n        #region Constructor methods\n\n        object objectReference = null; //prevents disposing parent object if sharing data (GetSubRect(..), casting...)\n        Action<object> parentDestructor = null;\n\n        private Image()\n        {\n            this.ColorInfo = ColorInfo.GetInfo<TColor>(); //an early init is needed during deserialization\n        }\n\n        /// <summary>\n        /// Creates an unmanaged image by pinning the provided array.\n        /// <para>No data is copied.</para>\n        /// </summary>\n        /// <param name=\"array\">Array to lock.</param>\n        /// <returns>Unmanaged image.</returns>\n        public static Image<TColor> Lock(TColor[,] array)\n        {\n            GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);\n            int width = array.GetLength(1);\n            int height = array.GetLength(0);\n\n            var image = new Image<TColor>(handle.AddrOfPinnedObject(), width, height, ColorInfo.GetInfo<TColor>().Size * width, \n                                          handle, x => ((GCHandle)x).Free());\n\n            return image;\n        }\n\n        /// <summary>\n        /// Creates an unmanaged image representation from the provided array and image width (un-flattens the array).\n        /// <para>No data is copied.</para>\n        /// </summary>\n        /// <param name=\"rawImageArray\">Raw-byte image data array to lock.</param>\n        /// <param name=\"width\">\n        /// Image width.\n        /// <para>Data length and the provided width must produce an integer height.</para>\n        /// </param>\n        /// <returns>Unmanaged image.</returns>\n        public static Image<TColor> Lock(byte[] rawImageArray, int width)\n        {\n            GCHandle handle = GCHandle.Alloc(rawImageArray, GCHandleType.Pinned);\n\n            float height = (float)rawImageArray.Length / (width * ColorInfo.GetInfo<TColor>().Size);\n            if (height != (int)height)\n                throw new ArgumentException(\"The calculated height is not integer. There is a mismatch between given width, the data length and the image pixel type.\");\n\n            var image = new Image<TColor>(handle.AddrOfPinnedObject(), width, (int)height, ColorInfo.GetInfo<TColor>().Size * width,\n                                          handle, x => ((GCHandle)x).Free());\n\n            return image;\n        }\n\n        /// <summary>\n        /// Constructs an image from unmanaged data. Data is shared.\n        /// </summary>\n        /// <param name=\"imageData\">Pointer to unmanaged data.</param>\n        /// <param name=\"width\">Image width.</param>\n        /// <param name=\"height\">Image height.</param>\n        /// <param name=\"stride\">Image stride.</param>\n        /// <param name=\"parentReference\">To prevent object from deallocating use this parameter.</param>\n        /// <param name=\"parentDestructor\">If a parent needs to be destroyed or release use this function. (e.g. unpin object - GCHandle)</param>\n        public Image(IntPtr imageData, int width, int height, int stride, object parentReference = null, Action<object> parentDestructor = null)\n            :this()\n        {\n            initializeProperties(this, imageData, width, height, stride);\n            this.objectReference = parentReference;\n            this.parentDestructor = parentDestructor;\n        }\n\n        private static void initializeProperties(Image<TColor> im, IntPtr imageData, int width, int height, int stride)\n        {\n            im.ImageData = imageData;\n            im.Width = width;\n            im.Height = height;\n            im.Stride = stride;\n        }\n\n        #endregion\n\n        #region Properties\n\n        /// <summary>\n        /// Gets unmanaged image data.\n        /// </summary>\n        public IntPtr ImageData { get; private set; }\n        /// <summary>\n        /// Gets image width.\n        /// </summary>\n        public int Width { get; private set; }\n        /// <summary>\n        /// Gets image height.\n        /// </summary>\n        public int Height { get; private set; }\n        /// <summary>\n        /// Gets image stride - number of bytes per image row.\n        /// </summary>\n        public int Stride { get; private set; }\n        /// <summary>\n        /// Gets image size.\n        /// </summary>\n        public Size Size { get { return new Size(this.Width, this.Height); } }\n        /// <summary>\n        /// Gets image color info.\n        /// </summary>\n        public ColorInfo ColorInfo { get; protected set; } //set in \n\n        #endregion\n\n        #region Basic helper methods\n\n        /// <summary>\n        /// Gets image data at specified location.\n        /// </summary>\n        /// <param name=\"row\">Row index.</param>\n        /// <param name=\"col\">Column index.</param>\n        /// <returns>Data pointer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public IntPtr GetData(int row, int col)\n        {\n            if (col < 0 || col >= this.Width)\n                throw new ArgumentOutOfRangeException(\"Column index is out of range: \" + col);\n\n            return this.GetData(row) + col * this.ColorInfo.Size;\n        }\n\n        /// <summary>\n        /// Gets image data at specified location.\n        /// </summary>\n        /// <param name=\"row\">Row index.</param>\n        /// <returns>Data pointer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public IntPtr GetData(int row)\n        {\n            if (row < 0 || row >= this.Height)\n                throw new ArgumentOutOfRangeException(\"Row index is out of range: \" + row);\n\n            return this.ImageData + row * this.Stride;\n        }\n\n        /// <summary>\n        /// Gets sub-image from specified area. Data is shared.\n        /// </summary>\n        /// <param name=\"rect\">Area of an image for sub-image creation.</param>\n        /// <returns>Sub-image.</returns>\n        public Image<TColor> GetSubRect(Rectangle rect)\n        {\n            if (rect.Right > this.Width || rect.Bottom > this.Height) //Location will be verified through GetData(...) function\n                throw new ArgumentOutOfRangeException();\n\n            object objRef = this.objectReference ?? this; //always show at the root\n\n            IntPtr data = GetData(rect.Y, rect.X);\n            return new Image<TColor>(data, rect.Width, rect.Height, this.Stride, objRef);\n        }\n\n        /// <summary>\n        /// Gets sub-image from specified area. Data is shared.\n        /// </summary>\n        /// <param name=\"rect\">Area of an image for sub-image creation.</param>\n        /// <returns>Sub-image.</returns>\n        IImage IImage.GetSubRect(Rectangle rect)\n        {\n            return this.GetSubRect(rect);\n        }\n\n        #endregion\n\n        #region IEquatable, IDisposable\n\n        /// <summary>\n        /// Compares this image to another image. Only pointer location and image size are compared.\n        /// There is no data compassion.\n        /// </summary>\n        /// <param name=\"other\">Other image.</param>\n        /// <returns>Whether two images are equal or not.</returns>\n        public bool Equals(IImage other)\n        {\n            if (other != null &&\n                this.ImageData == other.ImageData &&\n                this.Size == other.Size)\n            {\n                return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Compares this image to another object. Internally the function overload is called.\n        /// </summary>\n        /// <param name=\"obj\">Other.</param>\n        /// <returns>Is the image equal to an object or not.</returns>\n        public override bool Equals(object obj)\n        {\n            return this.Equals(obj as IImage);\n        }\n\n        /// <summary>\n        /// Image's hash code. Pointer address is used as hash code.\n        /// </summary>\n        /// <returns>Image's hash code.</returns>\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                return (int)this.ImageData.ToInt64(); //support for 64-bit architecture\n            }\n        }\n\n        bool isDisposed = false;\n\n        /// <summary>\n        /// Disposes generic image. \n        /// In case if data is allocated it is released.\n        /// If data is shared parent reference (if exists) and parent handle (if exist) is released.\n        /// </summary>\n        public void Dispose()\n        {\n            if (isDisposed) return; //if this function is called for the first time\n\n            if (this.parentDestructor != null)\n                this.parentDestructor(objectReference);\n\n            this.parentDestructor = null;\n            this.objectReference = null;\n\n            isDisposed = true;\n        }\n\n        /// <summary>\n        /// Disposes the image.\n        /// </summary>\n        ~Image()\n        {\n            Dispose();\n        }\n\n        #endregion\n    }\n\n}\n"
  },
  {
    "path": "Source/Primitives2D/Box2D/Box2D.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Drawing;\n\nnamespace DotImaging.Primitives2D\n{\n    /// <summary>\n    /// Box2D equivalent of OpenCV's Box2D Class.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Box2D\n    {\n         /// <summary>\n        /// Gets empty structure.\n        /// </summary>\n        public static readonly Box2D Empty = new Box2D();\n\n        /// <summary>\n        /// Area center.\n        /// </summary>\n        public PointF Center;\n        /// <summary>\n        /// Area size.\n        /// </summary>\n        public SizeF Size;\n        /// <summary>\n        /// Angle in degrees.\n        /// </summary>\n        public float Angle;\n\n        /// <summary>\n        /// Creates new structure from area and angle.\n        /// </summary>\n        /// <param name=\"rect\">Area.</param>\n        /// <param name=\"angle\">Angle in degrees.</param>\n        public Box2D(RectangleF rect, float angle)\n            :this(rect.Center(), rect.Size, angle)\n        {}\n\n        /// <summary>\n        /// Creates new structure from area and angle.\n        /// </summary>\n        /// <param name=\"center\">Box2D center.</param>\n        /// <param name=\"size\">Box 2D size.</param>\n        /// <param name=\"angle\">Angle in degrees.</param>\n        public Box2D(PointF center, SizeF size, float angle)\n        {\n            this.Center = new PointF(center.X, center.Y);\n            this.Size = size;\n            this.Angle = angle;\n        }\n\n        /// <summary>\n        /// Returns true if the structure is  empty.\n        /// </summary>\n        public bool IsEmpty\n        {\n            get { return this.Equals(Empty); }\n        }\n\n        /// <summary>\n        /// Gets the minimum enclosing rectangle for this box.\n        /// </summary>\n        public RectangleF GetMinArea()\n        { \n            var vertices = this.GetVertices();\n\n            float minX = vertices.Min(x => x.X);\n            float maxX = vertices.Max(x => x.X);\n\n            float minY = vertices.Min(x => x.Y);\n            float maxY = vertices.Max(x => x.Y);\n\n            return new RectangleF(minX, minY, maxX - minX, maxY - minY);\n        }\n\n        /// <summary>\n        /// Gets vertices.\n        /// </summary>\n        /// <returns>Vertices.</returns>\n        public PointF[] GetVertices()\n        {\n            PointF center = this.Center;\n            var angleDeg = this.Angle;\n          \n            PointF[] nonRotatedVertices = getNonRotatedVertices();\n            PointF[] rotatedVertices = nonRotatedVertices.Select(x=> new PointF(x.X - center.X, x.Y - center.Y)) //translate to (0,0)\n                                                         .Select(x => x.Rotate(angleDeg)) //rotate\n                                                         .Select(x => new PointF(x.X + center.X, x.Y + center.Y)) //translate back\n                                                         .ToArray();\n\n            return rotatedVertices;\n        }\n\n        private PointF[] getNonRotatedVertices()\n        {\n            float offsetX = this.Size.Width / 2;\n            float offsetY = this.Size.Height / 2;\n\n            return new PointF[] \n            {\n                new PointF(this.Center.X - offsetX, this.Center.Y - offsetY), //left-upper\n                new PointF(this.Center.X + offsetX, this.Center.Y - offsetY), //right-upper\n                new PointF(this.Center.X + offsetX, this.Center.Y + offsetY), //right-bottom\n                new PointF(this.Center.X - offsetX, this.Center.Y + offsetY) //left-bottom\n            };\n        }\n\n        /// <summary>\n        /// Converts Rectangle to the Box2D representation (angle is zero).\n        /// </summary>\n        /// <param name=\"rect\">Rectangle to convert.</param>\n        /// <returns>Box2D representation.</returns>\n        public static implicit operator Box2D(Rectangle rect)\n        {\n            return new Box2D(rect, 0);\n        }\n\n        /// <summary>\n        /// Converts RectangleF to the Box2D representation (angle is zero).\n        /// </summary>\n        /// <param name=\"rect\">Rectangle to convert.</param>\n        /// <returns>Box2D representation.</returns>\n        public static implicit operator Box2D(RectangleF rect)\n        {\n            return new Box2D(rect, 0);\n        }\n\n        /// <summary>\n        /// Determines whether two objects are equal.\n        /// </summary>\n        /// <param name=\"obj\">Object to test.</param>\n        /// <returns>True if two objects are equal, false otherwise.</returns>\n        public override bool Equals(object obj)\n        {\n            if (obj is Box2D == false) return false;\n\n            var b = (Box2D)obj;\n            return b.Center.Equals(this.Center) && b.Angle.Equals(this.Angle);\n        }\n\n        /// <summary>\n        /// Gets hash-code for the structure.\n        /// </summary>\n        /// <returns>Hash-code.</returns>\n        public override int GetHashCode()\n        {\n            return base.GetHashCode();\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Primitives2D/Circle/Circle.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nnamespace DotImaging.Primitives2D\n{\n    // Accord Math Library\n    // The Accord.NET Framework\n    // http://accord-framework.net\n    //\n    // Copyright © César Souza, 2009-2014\n    // cesarsouza at gmail.com\n    //\n    // Copyright © Darko Jurić, 2014-2019\n    // darko.juric2 at gmail.com\n    //\n    //    This library is free software; you can redistribute it and/or\n    //    modify it under the terms of the GNU Lesser General Public\n    //    License as published by the Free Software Foundation; either\n    //    version 2.1 of the License, or (at your option) any later version.\n    //\n    //    This library is distributed in the hope that it will be useful,\n    //    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    //    Lesser General Public License for more details.\n    //\n    //    You should have received a copy of the GNU Lesser General Public\n    //    License along with this library; if not, write to the Free Software\n    //    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n    //\n\n    using System.Drawing;\n\n    /// <summary>\n    ///   2D circle class.\n    /// </summary>\n    public struct Circle\n    {\n        /// <summary>\n        /// Horizontal center coordinate.\n        /// </summary>\n        public int X;\n        /// <summary>\n        /// Vertical center coordinate.\n        /// </summary>\n        public int Y;\n        /// <summary>\n        /// Circle radius.\n        /// </summary>\n        public int Radius;\n\n        /// <summary>\n        /// Gets or sets circle's location.\n        /// </summary>\n        public Point Center\n        {\n            get { return new Point(X, Y); }\n            set\n            {\n                this.X = value.X;\n                this.Y = value.Y;\n            }\n        }\n\n        /// <summary>\n        /// Creates a new instance of an <see cref=\"CircleF\"/> structure.\n        /// </summary>\n        /// <param name=\"position\">Center position.</param>\n        /// <param name=\"radius\">Circle radius.</param>\n        public Circle(Point position, int radius)\n            :this(position.X, position.Y, radius)\n        {}\n\n        /// <summary>\n        /// Creates a new instance of an <see cref=\"Circle\"/> structure.\n        /// </summary>\n        /// <param name=\"x\">Horizontal center position.</param>\n        /// <param name=\"y\">Vertical center position.</param>\n        /// <param name=\"radius\">Circle radius.</param>\n        public Circle(int x, int y, int radius)\n        {\n            this.X = x;\n            this.Y = y;\n            this.Radius = radius;\n        }\n\n        /// <summary>\n        ///   Gets the area of the circle (πR²).\n        /// </summary>\n        /// \n        public double Area\n        {\n            get { return Radius * Radius * System.Math.PI; }\n        }\n\n        /// <summary>\n        ///   Gets the circumference of the circle (2πR).\n        /// </summary>\n        /// \n        public double Circumference\n        {\n            get { return 2 * Radius * System.Math.PI; }\n        }\n\n        /// <summary>\n        ///   Gets the diameter of the circle (2R).\n        /// </summary>\n        /// \n        public int Diameter\n        {\n            get { return 2 * Radius; }\n        }\n\n        /// <summary>\n        ///   Computes the distance from circle to point.\n        /// </summary>\n        /// \n        /// <param name=\"point\">The point to have its distance from the circle computed.</param>\n        /// \n        /// <returns>The distance from <paramref name=\"point\"/> to this circle.</returns>\n        /// \n        public double DistanceToPoint(Point point)\n        {\n            var centerDiff = this.Center.DistanceTo(point);\n            return System.Math.Abs(centerDiff - Radius);\n        }\n\n        /// <summary>\n        /// Converts integer into floating-point representation.\n        /// </summary>\n        /// <param name=\"circle\">Integer circle representation.</param>\n        /// <returns>Floating-point circle representation.</returns>\n        public static implicit operator CircleF(Circle circle)\n        {\n            return new CircleF(circle.X, circle.Y, circle.Radius);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Primitives2D/Circle/CircleF.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nnamespace DotImaging.Primitives2D\n{\n    // Accord Math Library\n    // The Accord.NET Framework\n    // http://accord-framework.net\n    //\n    // Copyright © César Souza, 2009-2014\n    // cesarsouza at gmail.com\n    //\n    // Copyright © Darko Jurić, 2014-2019\n    // darko.juric2 at gmail.com\n    //\n    //\n    //    This library is free software; you can redistribute it and/or\n    //    modify it under the terms of the GNU Lesser General Public\n    //    License as published by the Free Software Foundation; either\n    //    version 2.1 of the License, or (at your option) any later version.\n    //\n    //    This library is distributed in the hope that it will be useful,\n    //    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    //    Lesser General Public License for more details.\n    //\n    //    You should have received a copy of the GNU Lesser General Public\n    //    License along with this library; if not, write to the Free Software\n    //    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n    //\n\n    using System.Drawing;\n\n    /// <summary>\n    ///   2D circle class.\n    /// </summary>\n    public struct CircleF\n    {\n        /// <summary>\n        /// Horizontal center coordinate.\n        /// </summary>\n        public float X;\n        /// <summary>\n        /// Vertical center coordinate.\n        /// </summary>\n        public float Y;\n        /// <summary>\n        /// Circle radius.\n        /// </summary>\n        public float Radius;\n\n        /// <summary>\n        /// Gets or sets circle's location.\n        /// </summary>\n        public PointF Center\n        {\n            get { return new PointF(X, Y); }\n            set \n            {\n                this.X = value.X;\n                this.Y = value.Y;\n            }\n        }\n\n        /// <summary>\n        /// Creates a new instance of an <see cref=\"CircleF\"/> structure.\n        /// </summary>\n        /// <param name=\"position\">Center position.</param>\n        /// <param name=\"radius\">Circle radius.</param>\n        public CircleF(PointF position, float radius)\n            : this(position.X, position.Y, radius)\n        { }\n\n        /// <summary>\n        /// Creates a new instance of an <see cref=\"CircleF\"/> structure.\n        /// </summary>\n        /// <param name=\"x\">Horizontal center position.</param>\n        /// <param name=\"y\">Vertical center position.</param>\n        /// <param name=\"radius\">Circle radius.</param>\n        public CircleF(float x, float y, float radius)\n        {\n            this.X = x;\n            this.Y = y;\n            this.Radius = radius;\n        }\n\n        /// <summary>\n        ///   Gets the area of the circle (πR²).\n        /// </summary>\n        /// \n        public double Area\n        {\n            get { return Radius * Radius * System.Math.PI; }\n        }\n\n        /// <summary>\n        ///   Gets the circumference of the circle (2πR).\n        /// </summary>\n        /// \n        public double Circumference\n        {\n            get { return 2 * Radius * System.Math.PI; }\n        }\n\n        /// <summary>\n        ///   Gets the diameter of the circle (2R).\n        /// </summary>\n        /// \n        public float Diameter\n        {\n            get { return 2 * Radius; }\n        }\n\n        /// <summary>\n        ///   Creates a new <see cref=\"Circle\"/> from three non-linear points.\n        /// </summary>\n        /// \n        /// <param name=\"p1\">The first point.</param>\n        /// <param name=\"p2\">The second point.</param>\n        /// <param name=\"p3\">The third point.</param>\n        /// \n        public CircleF(PointF p1, PointF p2, PointF p3)\n        {\n            // ya = ma * (x - x1) + y1\n            // yb = mb * (x - x2) + y2\n            //\n            // ma = (y2 - y1) / (x2 - x1)\n            // mb = (y3 - y2) / (x3 - x2)\n            double ma = (p2.Y - p1.Y) / (p2.X - p1.X);\n            double mb = (p3.Y - p2.Y) / (p3.X - p2.X);\n\n            //       (ma * mb * (y1 - y3) + mb * (x1 + x2) - ma * (x2 + x3)\n            // x = ----------------------------------------------------------\n            //                          2 * (mb - ma)\n            double x = (ma * mb * (p1.Y - p3.Y) + mb * (p1.X + p2.Y) - ma * (p2.X + p3.X)) / (2 * (mb - ma));\n            double y = ma * (x - p1.X) + p1.Y;\n\n            this.X = (float)x;\n            this.Y = (float)y;\n            this.Radius = (float)System.Math.Sqrt((this.X - p1.X) * (this.X - p1.X) + (this.Y - p1.Y) * (this.Y - p1.Y)); //Euclidean distance\n        }\n\n        /// <summary>\n        ///   Computes the distance from circle to point.\n        /// </summary>\n        /// \n        /// <param name=\"point\">The point to have its distance from the circle computed.</param>\n        /// \n        /// <returns>The distance from <paramref name=\"point\"/> to this circle.</returns>\n        /// \n        public double DistanceToPoint(PointF point)\n        {\n            var centerDiff = this.Center.DistanceTo(point);\n            return System.Math.Abs(centerDiff - Radius);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Primitives2D/Ellipse/Ellipse.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Drawing;\n\nnamespace DotImaging.Primitives2D\n{\n    /// <summary>\n    /// Ellipse structure containing center and ellipse size.\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Ellipse\n    {\n        /// <summary>\n        /// Creates a new ellipse.\n        /// </summary>\n        /// <param name=\"center\">Ellipse center.</param>\n        /// <param name=\"size\">Ellipse size.</param>\n        /// <param name=\"angle\">Angle in degrees.</param>\n        public Ellipse(PointF center, SizeF size, float angle = 0)\n        {\n            this.Center = center;\n            this.Size = size;\n            this.Angle = angle;\n        }\n\n        /// <summary>\n        /// Area center.\n        /// </summary>\n        public PointF Center;\n        /// <summary>\n        /// Area size.\n        /// </summary>\n        public SizeF Size;\n        /// <summary>\n        /// Angle in degrees.\n        /// </summary>\n        public float Angle;\n\n        /// <summary>\n        /// Converts Box2D to Ellipse representation.\n        /// </summary>\n        /// <param name=\"box\">Box to convert.</param>\n        /// <returns>Ellipse.</returns>\n        public static explicit operator Ellipse(Box2D box)\n        {\n            return new Ellipse { Center = box.Center, Size = box.Size, Angle = box.Angle };\n        }\n\n        /// <summary>\n        /// Converts Ellipse to Box2D representation.\n        /// </summary>\n        /// <param name=\"ellipse\">Ellipse to convert.</param>\n        /// <returns>Box2D.</returns>\n        public static explicit operator Box2D(Ellipse ellipse)\n        {\n            return new Box2D { Center = ellipse.Center, Size = ellipse.Size, Angle = ellipse.Angle };\n        }\n\n        /// <summary>\n        /// Fits the covariance matrix (or 2nd moment matrix) to the ellipse by calculating eigen-vectors and values.\n        /// </summary>\n        /// <param name=\"covMatrix\">Covariance matrix (or 2nd moment matrix).</param>\n        /// <param name=\"center\">Center of the ellipse.</param>\n        /// <returns>Ellipse.</returns>\n        public static Ellipse Fit(double[,] covMatrix, PointF center = default(PointF))\n        {\n            if (covMatrix.GetLength(0) != 2 || covMatrix.GetLength(1) != 2)\n                throw new ArgumentException(\"Covariance matrix must have the same dimensions, and the dimension length must be 2!\");\n\n            return Fit(covMatrix[0, 0], covMatrix[0, 1], covMatrix[1, 1], center);\n        }\n\n        /// <summary>\n        /// Fits the covariance matrix (or 2nd moment matrix) to the ellipse by calculating eigen-vectors and values.\n        /// </summary>\n        /// <param name=\"a\">[0, 0] value of the covariance matrix.</param>\n        /// <param name=\"b\">[0, 1] or [1, 0] value of the covariance matrix.</param>\n        /// <param name=\"c\">[1, 1] value of the covariance matrix.</param>\n        /// <param name=\"center\">Center of the ellipse.</param>\n        /// <param name=\"success\">Returns true if both calculated eigen-values are positive.</param>\n        /// <returns>Ellipse.</returns>\n        public static Ellipse Fit(double a, double b, double c, PointF center, out bool success)\n        {  \n            var acDiff = a - c;\n            var acSum = a + c;\n\n            //A * X = lambda * X => solve quadratic equation => lambda1/2 = [a + c +/- sqrt((a-c)^2 + 4b^2)]  / 2\n            var sqrtDiscriminant = System.Math.Sqrt(acDiff * acDiff + 4 * b * b);\n\n            var eigVal1 = (acSum + sqrtDiscriminant) / 2;\n            var eigVal2 = (acSum - sqrtDiscriminant) / 2;\n\n            //A * X = lambda * X => y / x = b / (lambda - c); where lambda is the first eigen-value\n            var angle = System.Math.Atan2(2 * b, (acDiff + sqrtDiscriminant));\n\n            success = eigVal1 > 0 && eigVal2 > 0;\n            return new Ellipse\n            {\n                Center = center,\n                Size = new SizeF \n                {\n                    Width = (float)System.Math.Sqrt(eigVal1) * 4,\n                    Height =(float)System.Math.Sqrt(eigVal2) * 4\n                },\n                Angle = (float)(angle * 180 / Math.PI) \n            };\n        }\n\n        /// <summary>\n        /// Fits the covariance matrix (or 2nd moment matrix) to the ellipse by calculating eigen-vectors and values.\n        /// </summary>\n        /// <param name=\"a\">[0, 0] value of the covariance matrix.</param>\n        /// <param name=\"b\">[0, 1] or [1, 0] value of the covariance matrix.</param>\n        /// <param name=\"c\">[1, 1] value of the covariance matrix.</param>\n        /// <param name=\"center\">Center of the ellipse.</param>\n        /// <returns>Ellipse.</returns>\n        public static Ellipse Fit(double a, double b, double c, PointF center = default(PointF))\n        {\n            bool success;\n            return Fit(a, b, c, center, out success);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Primitives2D/Point/Point'1.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nnamespace DotImaging.Primitives2D\n{\n    /// <summary>\n    /// Represents the 2D (X, Y) pair.\n    /// </summary>\n    /// <typeparam name=\"T\">Value type.</typeparam>\n    public struct Point<T>\n        where T : struct\n    {\n        /// <summary>\n        /// Creates a new point.\n        /// </summary>\n        /// <param name=\"x\">X coordinate.</param>\n        /// <param name=\"y\">Y coordinate.</param>\n        public Point(T x, T y)\n        {\n            X = x;\n            Y = y;\n        }\n\n        /// <summary>\n        /// Gets or sets X coordinate.\n        /// </summary>\n        public T X;\n        \n        /// <summary>\n        /// Gets or sets Y coordinate.\n        /// </summary>\n        public T Y;\n\n        /// <summary>\n        /// Determines whether the provided object is equal to the current object.\n        /// </summary>\n        /// <param name=\"obj\">Other object to compare with.</param>\n        /// <returns>True if the two objects are equal, false otherwise.</returns>\n        public override bool Equals(object obj)\n        {\n            if (obj is Point<T> == false)\n                return false;\n\n            var pt = (Point<T>)obj;\n            return this.X.Equals(pt.X) && this.Y.Equals(pt.Y);\n        }\n\n        /// <summary>\n        /// Gets the hash code.\n        /// </summary>\n        /// <returns>Hash code.</returns>\n        public override int GetHashCode()\n        {\n            return this.X.GetHashCode() ^ this.Y.GetHashCode();\n        }\n\n        /// <summary>\n        /// Gets the string representation of the object.\n        /// </summary>\n        /// <returns>String representation.</returns>\n        public override string ToString()\n        {\n            return string.Format(\"{{X={0}, Y={1}}}\", X, Y);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Primitives2D/Point/PointExtensions.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Drawing;\n\nnamespace DotImaging.Primitives2D\n{\n    /// <summary>\n    /// Provides point extension methods.\n    /// </summary>\n    public static class Point32iExtensions\n    {\n        /// <summary>\n        /// Transforms point to the lower pyramid level.\n        /// </summary>\n        /// <param name=\"p\">Point.</param>\n        /// <param name=\"levels\">Specifies how many levels to take.</param>\n        /// <param name=\"factor\">Specifies the pyramid scale factor.</param>\n        /// <returns>Scaled point.</returns>\n        public static PointF UpScale(this Point p, int levels = 1, double factor = 2)\n        {\n            var upscaleFactor = (float)System.Math.Pow(factor, levels);\n\n            return new PointF\n            {\n                X = p.X * upscaleFactor,\n                Y = p.Y * upscaleFactor\n            };\n        }\n\n        /// <summary>\n        /// Transforms point to the higher pyramid level.\n        /// </summary>\n        /// <param name=\"p\">Point.</param>\n        /// <param name=\"levels\">Specifies how many levels to take.</param>\n        /// <param name=\"factor\">Specifies the pyramid scale factor.</param>\n        /// <returns>Scaled point.</returns>\n        public static PointF DownScale(this Point p, int levels = 1, double factor = 2)\n        {\n            var downscaleFactor = (float)(1 / System.Math.Pow(factor, levels));\n\n            return new PointF\n            {\n                X = p.X * downscaleFactor,\n                Y = p.Y * downscaleFactor\n            };\n        }\n\n        /// <summary>\n        /// Translates the point by the specified offset.\n        /// </summary>\n        /// <param name=\"point\">The point to offset.</param>\n        /// <param name=\"offset\">Offset to be added.</param>\n        /// <returns>Translated point.</returns>\n        public static Point Add(this Point point, Point offset)\n        {\n            return new Point\n            {\n                X = point.X + offset.X,\n                Y = point.Y + offset.Y\n            };\n        }\n\n        /// <summary>\n        /// Subtracts the point by the specified offset.\n        /// </summary>\n        /// <param name=\"point\">The point to subtract.</param>\n        /// <param name=\"offset\">Subtract factor.</param>\n        /// <returns>Translated point.</returns>\n        public static Point Subtract(this Point point, Point offset)\n        {\n            return new Point\n            {\n                X = point.X - offset.X,\n                Y = point.Y - offset.Y\n            };\n        }\n\n        /// <summary>\n        /// Calculates the Euclidean distance between two points.\n        /// </summary>\n        /// <param name=\"pointA\">First point.</param>\n        /// <param name=\"pointB\">Second point.</param>\n        /// <returns>Euclidean distance between the points.</returns>\n        public static double DistanceTo(this Point pointA, Point pointB)\n        {\n            var distnace = System.Math.Sqrt((pointA.X - pointB.X) * (pointA.X - pointB.X) + (pointA.Y - pointB.Y) * (pointA.Y - pointB.Y)); //Euclidean distance\n            return distnace;\n        }\n\n        /// <summary>\n        /// Rotates one point around another\n        /// </summary>\n        /// <param name=\"pointToRotate\">The point to rotate.</param>\n        /// <param name=\"angleDeg\">The rotation angle in degrees.</param>\n        /// <param name=\"centerPoint\">The center point of rotation.</param>\n        /// <returns>Rotated point</returns>\n        public static PointF Rotate(this Point pointToRotate, double angleDeg, Point centerPoint)\n        {\n            //taken from: http://stackoverflow.com/questions/13695317/rotate-a-point-around-another-point and modified\n\n            double angleInRadians = angleDeg * (Math.PI / 180);\n            double cosTheta = Math.Cos(angleInRadians);\n            double sinTheta = Math.Sin(angleInRadians);\n\n            return new PointF\n            {\n                X =\n                    (float)\n                    (cosTheta * (pointToRotate.X - centerPoint.X) -\n                    sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),\n                Y =\n                    (float)\n                    (sinTheta * (pointToRotate.X - centerPoint.X) +\n                    cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)\n            };\n        }\n\n        /// <summary>\n        /// Rotates one point around the (0,0).\n        /// </summary>\n        /// <param name=\"pointToRotate\">The point to rotate.</param>\n        /// <param name=\"angleDeg\">The rotation angle in degrees.</param>\n        /// <returns>Rotated point</returns>\n        public static PointF Rotate(this Point pointToRotate, double angleDeg)\n        {\n            return pointToRotate.Rotate(angleDeg, Point.Empty);\n        }\n\n        /// <summary>\n        /// Negates point coordinates.\n        /// </summary>\n        /// <param name=\"point\">The point to negate.</param>\n        /// <returns>Point with negated coordinates.</returns>\n        public static Point Negate(this Point point)\n        {\n            return new Point\n            {\n                X = -point.X,\n                Y = -point.Y\n            };\n        }\n    }\n\n    /// <summary>\n    /// Provides point extension methods.\n    /// </summary>\n    public static class Point32fExtensions\n    {\n        /// <summary>\n        /// Transforms point to the lower pyramid level.\n        /// </summary>\n        /// <param name=\"p\">Point.</param>\n        /// <param name=\"levels\">Specifies how many levels to take.</param>\n        /// <param name=\"factor\">Specifies the pyramid scale factor.</param>\n        /// <returns>Scaled point.</returns>\n        public static PointF UpScale(this PointF p, int levels = 1, double factor = 2)\n        {\n            var upscaleFactor = (float)System.Math.Pow(factor, levels);\n\n            return new PointF\n            {\n                X = p.X * upscaleFactor,\n                Y = p.Y * upscaleFactor\n            };\n        }\n\n        /// <summary>\n        /// Transforms point to the higher pyramid level.\n        /// </summary>\n        /// <param name=\"p\">Point.</param>\n        /// <param name=\"levels\">Specifies how many levels to take.</param>\n        /// <param name=\"factor\">Specifies the pyramid scale factor.</param>\n        /// <returns>Scaled point.</returns>\n        public static PointF DownScale(this PointF p, int levels = 1, double factor = 2)\n        {\n            var downscaleFactor = (float)(1 / System.Math.Pow(factor, levels));\n\n            return new PointF\n            {\n                X = p.X * downscaleFactor,\n                Y = p.Y * downscaleFactor\n            };\n        }\n\n        /// <summary>\n        /// Translates the point by the specified offset.\n        /// </summary>\n        /// <param name=\"point\">The point to offset.</param>\n        /// <param name=\"offset\">Offset to be added.</param>\n        /// <returns>Translated point.</returns>\n        public static PointF Add(this PointF point, PointF offset)\n        {\n            return new PointF\n            {\n                X = point.X + offset.X,\n                Y = point.Y + offset.Y\n            };\n        }\n\n        /// <summary>\n        /// Subtracts the point by the specified offset.\n        /// </summary>\n        /// <param name=\"point\">The point to subtract.</param>\n        /// <param name=\"offset\">Subtract factor.</param>\n        /// <returns>Translated point.</returns>\n        public static PointF Subtract(this PointF point, PointF offset)\n        {\n            return new PointF\n            {\n                X = point.X - offset.X,\n                Y = point.Y - offset.Y\n            };\n        }\n\n        /// <summary>\n        /// Calculates the Euclidean distance between two points.\n        /// </summary>\n        /// <param name=\"pointA\">First point.</param>\n        /// <param name=\"pointB\">Second point.</param>\n        /// <returns>Euclidean distance between the points.</returns>\n        public static double DistanceTo(this PointF pointA, PointF pointB)\n        {\n            var distnace = System.Math.Sqrt((pointA.X - pointB.X) * (pointA.X - pointB.X) + (pointA.Y - pointB.Y) * (pointA.Y - pointB.Y)); //Euclidean distance\n           return distnace;\n        }\n\n        /// <summary>\n        /// Rotates one point around another\n        /// </summary>\n        /// <param name=\"pointToRotate\">The point to rotate.</param>\n        /// <param name=\"angleDeg\">The rotation angle in degrees.</param>\n        /// <param name=\"centerPoint\">The center point of rotation.</param>\n        /// <returns>Rotated point</returns>\n        public static PointF Rotate(this PointF pointToRotate, double angleDeg, PointF centerPoint)\n        {\n            //taken from: http://stackoverflow.com/questions/13695317/rotate-a-point-around-another-point and modified\n\n            double angleInRadians = angleDeg * (Math.PI / 180);\n            double cosTheta = Math.Cos(angleInRadians);\n            double sinTheta = Math.Sin(angleInRadians);\n\n            return new PointF\n            {\n                X =\n                    (float)\n                    (cosTheta * (pointToRotate.X - centerPoint.X) -\n                    sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),\n                Y =\n                    (float)\n                    (sinTheta * (pointToRotate.X - centerPoint.X) +\n                    cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)\n            };\n        }\n\n        /// <summary>\n        /// Rotates one point around the (0,0).\n        /// </summary>\n        /// <param name=\"pointToRotate\">The point to rotate.</param>\n        /// <param name=\"angleDeg\">The rotation angle in degrees.</param>\n        /// <returns>Rotated point</returns>\n        public static PointF Rotate(this PointF pointToRotate, double angleDeg)\n        {\n            return pointToRotate.Rotate(angleDeg, PointF.Empty);\n        }\n\n        /// <summary>\n        /// Rounds point coordinates.\n        /// </summary>\n        /// <param name=\"point\">Point.</param>\n        /// <returns>Integer point with rounded coordinates.</returns>\n        public static Point Round(this PointF point)\n        {\n            return Point.Round(point);\n        }\n\n        /// <summary>\n        /// Gets integer point representation by applying floor operation.\n        /// </summary>\n        /// <param name=\"p\">Point to truncate.</param>\n        /// <returns>Truncated point.</returns>\n        public static Point Floor(this PointF p)\n        {\n            return new Point\n            {\n                X = (int)p.X,\n                Y = (int)p.Y\n            };\n        }\n\n        /// <summary>\n        /// Negates point coordinates.\n        /// </summary>\n        /// <param name=\"point\">The point to negate.</param>\n        /// <returns>Point with negated coordinates.</returns>\n        public static PointF Negate(this PointF point)\n        {\n            return new PointF\n            {\n                X = -point.X,\n                Y = -point.Y\n            };\n        }\n    }\n\n    /// <summary>\n    /// Provides point collection extensions.\n    /// </summary>\n    public static class Point32fCollectionExtensions\n    {\n        //taken from:http://stackoverflow.com/questions/4243042/c-sharp-point-in-polygon and modified\n        /// <summary>\n        /// Checks whether the specified location is in the polygon.\n        /// </summary>\n        /// <param name=\"poly\">Polygon.</param>\n        /// <param name=\"x\">Horizontal coordinate.</param>\n        /// <param name=\"y\">VErtical coordinate.</param>\n        /// <returns>True if the point resides inside the polygon, false otherwise.</returns>\n        public static bool IsInPolygon(this IList<PointF> poly, float x, float y)\n        {\n            PointF p1, p2;\n\n            bool inside = false;\n\n            if (poly.Count < 3)\n            {\n                return inside;\n            }\n\n            var oldPoint = new PointF(poly[poly.Count - 1].X, poly[poly.Count - 1].Y);\n\n            for (int i = 0; i < poly.Count; i++)\n            {\n                var newPoint = new PointF(poly[i].X, poly[i].Y);\n\n                if (newPoint.X > oldPoint.X)\n                {\n                    p1 = oldPoint;\n                    p2 = newPoint;\n                }\n\n                else\n                {\n                    p1 = newPoint;\n                    p2 = oldPoint;\n                }\n\n\n                if ((newPoint.X < x) == (x <= oldPoint.X) && \n                    (y - (long)p1.Y) * (p2.X - p1.X) < (p2.Y - (long)p1.Y) * (x - p1.X))\n                {\n                    inside = !inside;\n                }\n\n\n                oldPoint = newPoint;\n            }\n\n            return inside;\n        }\n\n        /// <summary>\n        /// Gets the minimum bounding rectangle around the points.\n        /// </summary>\n        /// <param name=\"points\">Contour points.</param>\n        /// <returns>Bounding rectangle.</returns>\n        public static RectangleF BoundingRect(this IEnumerable<PointF> points)\n        {\n            if (points.Any() == false) return RectangleF.Empty;\n\n            float minX = Single.MaxValue, maxX = Single.MinValue,\n                  minY = Single.MaxValue, maxY = Single.MinValue;\n\n            foreach (var pt in points)\n            {\n                if (pt.X < minX)\n                    minX = pt.X;\n                if (pt.X > maxX)\n                    maxX = pt.X;\n\n                if (pt.Y < minY)\n                    minY = pt.Y;\n                if (pt.Y > maxY)\n                    maxY = pt.Y;\n            }\n\n            return new RectangleF(minX, minY, maxX - minX, maxY - minY);\n        }\n\n        /// <summary>\n        /// Gets the center of the mass of the contour.\n        /// </summary>\n        /// <param name=\"points\">Contour points.</param>\n        /// <returns>The center of the mass of the contour.</returns>\n        public static PointF Center(this IEnumerable<PointF> points)\n        {\n            PointF average = new PointF();\n            int nSamples = 0;\n\n            foreach (var pt in points)\n            {\n                average.X += pt.X;\n                average.Y += pt.Y;\n                nSamples++;\n            }\n\n            average.X /= nSamples;\n            average.Y /= nSamples;\n\n            return average;\n        }\n\n        /// <summary>\n        /// Determines whether the polygon forms rectangle.\n        /// </summary>\n        /// <param name=\"points\">Polygon.</param>\n        /// <returns>True if the polygon forms rectangle, false otherwise.</returns>\n        public static bool IsRectangle(this IEnumerable<PointF> points)\n        {\n            if (points.Count() != 4)\n                return false;\n\n            var rect = points.BoundingRect();\n\n            bool hasTopLeft = false, hasTopRight = false, hasBottomLeft = false, hasBottomRight = false;\n\n            foreach (var pt in points)\n            {\n                if (rect.Top == pt.Y)\n                {\n                    if (rect.X == pt.X)\n                        hasTopLeft = true;\n\n                    if (rect.Right == pt.X)\n                        hasTopRight = true;\n                }\n\n                if (rect.Bottom == pt.Y)\n                {\n                    if (rect.X == pt.X)\n                        hasBottomLeft = true;\n\n                    if (rect.Right == pt.X)\n                        hasBottomRight = true;\n                }\n            }\n\n            return hasTopLeft && hasTopRight && hasBottomLeft && hasBottomRight;\n        }\n    }\n\n    /// <summary>\n    /// Provides point collection extensions.\n    /// </summary>\n    public static class Point32iCollectionExtensions\n    {\n        //taken from:http://stackoverflow.com/questions/4243042/c-sharp-point-in-polygon and modified\n        /// <summary>\n        /// Checks whether the specified location is in the polygon.\n        /// </summary>\n        /// <param name=\"poly\">Polygon.</param>\n        /// <param name=\"x\">Horizontal coordinate.</param>\n        /// <param name=\"y\">VErtical coordinate.</param>\n        /// <returns>True if the point resides inside the polygon, false otherwise.</returns>\n        public static bool IsInPolygon(this IList<Point> poly, float x, float y)\n        {\n            Point p1, p2;\n\n            bool inside = false;\n\n            if (poly.Count < 3)\n            {\n                return inside;\n            }\n\n            var oldPoint = new Point(poly[poly.Count - 1].X, poly[poly.Count - 1].Y);\n\n            for (int i = 0; i < poly.Count; i++)\n            {\n                var newPoint = new Point(poly[i].X, poly[i].Y);\n\n                if (newPoint.X > oldPoint.X)\n                {\n                    p1 = oldPoint;\n                    p2 = newPoint;\n                }\n\n                else\n                {\n                    p1 = newPoint;\n                    p2 = oldPoint;\n                }\n\n\n                if ((newPoint.X < x) == (x <= oldPoint.X) &&\n                    (y - (long)p1.Y) * (p2.X - p1.X) < (p2.Y - (long)p1.Y) * (x - p1.X))\n                {\n                    inside = !inside;\n                }\n\n\n                oldPoint = newPoint;\n            }\n\n            return inside;\n        }\n\n        /// <summary>\n        /// Gets the minimum bounding rectangle around the points.\n        /// </summary>\n        /// <param name=\"points\">Contour points.</param>\n        /// <returns>Bounding rectangle.</returns>\n        public static Rectangle BoundingRect(this IEnumerable<Point> points)\n        {\n            if (points.Any() == false) return Rectangle.Empty;\n\n            int minX = Int32.MaxValue, maxX = Int32.MinValue,\n                minY = Int32.MaxValue, maxY = Int32.MinValue;\n\n            foreach (var pt in points)\n            {\n                if (pt.X < minX)\n                    minX = pt.X;\n                if (pt.X > maxX)\n                    maxX = pt.X;\n\n                if (pt.Y < minY)\n                    minY = pt.Y;\n                if (pt.Y > maxY)\n                    maxY = pt.Y;\n            }\n\n            return new Rectangle(minX, minY, maxX - minX, maxY - minY);\n        }\n\n        /// <summary>\n        /// Gets the center of the mass of the contour.\n        /// </summary>\n        /// <param name=\"points\">Contour points.</param>\n        /// <returns>The center of the mass of the contour.</returns>\n        public static PointF Center(this IEnumerable<Point> points)\n        {\n            PointF average = new PointF();\n            int nSamples = 0;\n\n            foreach (var pt in points)\n            {\n                average.X += pt.X;\n                average.Y += pt.Y;\n                nSamples++;\n            }\n\n            average.X /= nSamples;\n            average.Y /= nSamples;\n\n            return average;\n        }\n\n        /// <summary>\n        /// Determines whether the polygon forms rectangle.\n        /// </summary>\n        /// <param name=\"points\">Polygon.</param>\n        /// <returns>True if the polygon forms rectangle, false otherwise.</returns>\n        public static bool IsRectangle(this IEnumerable<Point> points)\n        {\n            if (points.Count() != 4)\n                return false;\n\n            var rect = points.BoundingRect();\n\n            bool hasTopLeft = false, hasTopRight = false, hasBottomLeft = false, hasBottomRight = false;\n\n            foreach (var pt in points)\n            {\n                if (rect.Top == pt.Y)\n                {\n                    if (rect.X == pt.X)\n                        hasTopLeft = true;\n\n                    if (rect.Right == pt.X)\n                        hasTopRight = true;\n                }\n\n                if (rect.Bottom == pt.Y)\n                {\n                    if (rect.X == pt.X)\n                        hasBottomLeft = true;\n\n                    if (rect.Right == pt.X)\n                        hasBottomRight = true;\n                }\n            }\n\n            return hasTopLeft && hasTopRight && hasBottomLeft && hasBottomRight;\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Primitives2D/Primitives2D.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp2.2</TargetFrameworks>\n    <AssemblyName>DotImaging.Primitives2D</AssemblyName>\n    <RootNamespace>DotImaging</RootNamespace>\n  </PropertyGroup>\n\t\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <DocumentationFile>bin\\DotImaging.Primitives2D.xml</DocumentationFile>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Drawing.Primitives\" Version=\"4.3.0\" />\n  </ItemGroup>\n  \n  <!-- NuGet -->\n  <PropertyGroup>\n    <Version>5.3.0</Version>\n\n    <PackageId>DotImaging.Primitives2D</PackageId>\n    <Description>Point, Size, Rectangle extensions, Circle, Ellipse, Box2D.</Description>\n    <PackageTags>imaging geometry structures 2D</PackageTags>\n\n    <Authors>Darko Jurić</Authors>\n    <Copyright>Darko Jurić</Copyright>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt</PackageLicenseUrl>\n    <PackageIconUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png</PackageIconUrl>\n    <PackageProjectUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</PackageProjectUrl>\n    <RepositoryUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</RepositoryUrl>\n\n    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    <PackageOutputPath>../../Deploy/NuGet/bin/</PackageOutputPath>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "Source/Primitives2D/Rectangle/RectangleExtensions.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\n\nnamespace DotImaging.Primitives2D\n{\n    /// <summary>\n    /// Provides extension methods for Rectangle and RectangleF structures.\n    /// </summary>\n    public static class RectangleExtennsions\n    {\n        /// <summary>\n        /// Gets intersection percent of two rectangles.\n        /// </summary>\n        /// <param name=\"rect1\">First rectangle.</param>\n        /// <param name=\"rect2\">Second rectangle.</param>\n        /// <returns>Intersection percent (e.g. 1 - full intersection, 0 - no intersection).</returns>\n        public static float IntersectionPercent(this Rectangle rect1, Rectangle rect2)\n        {\n            return RectangleFExtensions.IntersectionPercent(rect1, rect2);\n        }\n\n        /// <summary>\n        /// Gets the rectangle area.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>Area of the rectangle.</returns>\n        public static int Area(this Rectangle rect)\n        {\n            return rect.Width * rect.Height;\n        }\n\n        /// <summary>\n        /// Gets rectangle center.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>Center of the rectangle.</returns>\n        public static Point Center(this Rectangle rect)\n        {\n            return new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);\n        }\n\n        /// <summary>\n        /// Gets rectangle vertexes in clock-wise order staring from left-upper corner.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>Vertexes.</returns>\n        public static Point[] Vertices(this Rectangle rect)\n        {\n            return new Point[]\n            {\n                new Point(rect.X, rect.Y), //left-upper\n                new Point(rect.Right, rect.Y), //right-upper\n                new Point(rect.Right, rect.Bottom), //right-bottom\n                new Point(rect.X, rect.Bottom) //left-bottom\n            };\n        }\n\n        /// <summary>\n        /// Gets whether the rectangle has an empty area. It is different than <see cref=\"Rectangle.Empty\"/> property.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>True if the rectangle has an empty area.</returns>\n        public static bool IsEmptyArea(this Rectangle rect)\n        {\n            return rect.Width == 0 || rect.Height == 0;\n        }\n\n        /// <summary>\n        /// Gets the bounding rectangle of the rectangle collection.\n        /// </summary>\n        /// <param name=\"rectangles\">Rectangle collection.</param>\n        /// <returns>Bounding rectangle.</returns>\n        public static Rectangle BoundingRectangle(this IEnumerable<Rectangle> rectangles)\n        {\n            int minX = Int16.MaxValue, minY = Int16.MaxValue, maxX = Int16.MinValue, maxY = Int16.MinValue;\n\n            foreach (var r in rectangles)\n            {\n                if (r.Left < minX) minX = r.Left;\n                if (r.Top < minY) minY = r.Top;\n                if (r.Right > maxX) maxX = r.Right;\n                if (r.Bottom > maxY) maxY = r.Bottom;\n            }\n\n            return Rectangle.FromLTRB(minX, minY, maxX, maxY);\n        }\n    }\n\n    /// <summary>\n    /// <para>Defined functions can be used as object extensions.</para>\n    /// Provides extension methods for rectangle structure.\n    /// </summary>\n    public static class RectangleFExtensions\n    {\n        /// <summary>\n        /// Gets intersection percent of two rectangles.\n        /// </summary>\n        /// <param name=\"rect1\">First rectangle.</param>\n        /// <param name=\"rect2\">Second rectangle.</param>\n        /// <returns>Intersection percent (1 - full intersection, 0 - no intersection).</returns>\n        public static float IntersectionPercent(this RectangleF rect1, RectangleF rect2)\n        {\n            float rect1Area = rect1.Width * rect1.Height;\n            float rect2Area = rect2.Width * rect2.Height;\n\n            RectangleF interesectRect = RectangleF.Intersect(rect1, rect2);\n            float intersectRectArea = interesectRect.Width * interesectRect.Height;\n\n            float minRectArea = System.Math.Min(rect1Area, rect2Area);\n\n            return (float)intersectRectArea / minRectArea;\n        }\n\n        /// <summary>\n        /// Gets the rectangle area.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>Area of the rectangle.</returns>\n        public static float Area(this RectangleF rect)\n        {\n            return rect.Width * rect.Height;\n        }\n\n        /// <summary>\n        /// Gets rectangle center.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>Center of the rectangle.</returns>\n        public static PointF Center(this RectangleF rect)\n        {\n            return new PointF(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);\n        }\n\n        /// <summary>\n        /// Gets rectangle vertexes in clock-wise order staring from left-upper corner.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>Vertexes.</returns>\n        public static PointF[] Vertices(this RectangleF rect)\n        {\n            return new PointF[]\n            {\n                new PointF(rect.X, rect.Y), //left-upper\n                new PointF(rect.Right, rect.Y), //right-upper\n                new PointF(rect.Right, rect.Bottom), //right-bottom\n                new PointF(rect.X, rect.Bottom) //left-bottom\n            };\n        }\n\n        /// <summary>\n        /// Gets whether the rectangle has an empty area. It is different than <see cref=\"Rectangle.Empty\"/> property.\n        /// </summary>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <returns>True if the rectangle has an empty area.</returns>\n        public static bool IsEmptyArea(this RectangleF rect)\n        {\n            return rect.Width == 0 || rect.Height == 0;\n        }\n\n        /// <summary>\n        /// Gets the bounding rectangle of the rectangle collection.\n        /// </summary>\n        /// <param name=\"rectangles\">Rectangle collection.</param>\n        /// <returns>Bounding rectangle.</returns>\n        public static RectangleF BoundingRectangle(this IEnumerable<RectangleF> rectangles)\n        {\n            float minX = Int16.MaxValue, minY = Int16.MaxValue, maxX = Int16.MinValue, maxY = Int16.MinValue;\n\n            foreach (var r in rectangles)\n            {\n                if (r.Left < minX) minX = r.Left;\n                if (r.Top < minY) minY = r.Top;\n                if (r.Right > maxX) maxX = r.Right;\n                if (r.Bottom > maxY) maxY = r.Bottom;\n            }\n\n            return RectangleF.FromLTRB(minX, minY, maxX, maxY);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Primitives2D/Size/SizeExtensions.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System.Drawing;\n\nnamespace DotImaging.Primitives2D\n{\n    /// <summary>\n    /// <para>Defined functions can be used as object extensions.</para>\n    /// Provides size extension methods.\n    /// </summary>\n    public static class SizeExtensions\n    {\n        /// <summary>\n        /// Gets the size area.\n        /// </summary>\n        /// <param name=\"size\">Size.</param>\n        /// <returns>Area.</returns>\n        public static int Area(this Size size)\n        {\n            return size.Width * size.Height;\n        }\n\n        /// <summary>\n        /// Converts the specified size into the rectangle representation with zero offset.\n        /// </summary>\n        /// <param name=\"size\">Size.</param>\n        /// <returns>Rectangle with zero offset.</returns>\n        public static Rectangle ToRectangle(this Size size)\n        {\n            return new Rectangle(Point.Empty, size);\n        }\n\n        /// <summary>\n        /// Scales (multiplies) the provided size with the specified scale factor.\n        /// </summary>\n        /// <param name=\"size\">Size.</param>\n        /// <param name=\"scale\">Scale factor.</param>\n        /// <returns>Scaled size.</returns>\n        public static Size Scale(this Size size, float scale)\n        {\n            return new Size((int)(size.Width * scale),\n                            (int)(size.Height * scale));\n        }\n    }\n\n    /// <summary>\n    /// <para>Defined functions can be used as object extensions.</para>\n    /// Provides size extension methods.\n    /// </summary>\n    public static class SizeFExtensions\n    {\n        /// <summary>\n        /// Gets the size area.\n        /// </summary>\n        /// <param name=\"size\">Size.</param>\n        /// <returns>Area.</returns>\n        public static float Area(this SizeF size)\n        {\n            return size.Width * size.Height;\n        }\n\n        /// <summary>\n        /// Converts the specified size into the rectangle representation with zero offset.\n        /// </summary>\n        /// <param name=\"size\">Size.</param>\n        /// <returns>Rectangle with zero offset.</returns>\n        public static RectangleF ToRectangleF(this SizeF size)\n        {\n            return new RectangleF(PointF.Empty, size);\n        }\n\n        /// <summary>\n        /// Scales (multiplies) the provided size with the specified scale factor.\n        /// </summary>\n        /// <param name=\"size\">Size.</param>\n        /// <param name=\"scale\">Scale factor.</param>\n        /// <returns>Scaled size.</returns>\n        public static Size Scale(this Size size, float scale)\n        {\n            return new Size((int)(size.Width * scale),\n                            (int)(size.Height * scale));\n        }\n    }\n}\n"
  },
  {
    "path": "Source/UI.Image/.nuSpec/readmeUI.Image.txt",
    "content": "﻿Portable standalone UI elements invokable as extensions (image display).\n\nimage show\n   Bgr<byte>[,] image = new Bgr<byte>[480, 640];\n   image.SetValue<Bgr<byte>>(Bgr<byte>.Red);\n   image.Show();\n\n"
  },
  {
    "path": "Source/UI.Image/Base/CvCoreInvoke.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Security;\nusing System.Drawing;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Fonts\n    /// </summary>\n    public enum FontTypes\n    {\n        /// <summary>\n        /// HERSHEY_SIMPLEX\n        /// </summary>\n        HERSHEY_SIMPLEX = 0,\n        /// <summary>\n        /// HERSHEY_PLAIN\n        /// </summary>\n        HERSHEY_PLAIN = 1,\n        /// <summary>\n        /// HERSHEY_DUPLEX\n        /// </summary>\n        HERSHEY_DUPLEX = 2,\n        /// <summary>\n        /// HERSHEY_COMPLEX\n        /// </summary>\n        HERSHEY_COMPLEX = 3,\n        /// <summary>\n        /// HERSHEY_TRIPLEX\n        /// </summary>\n        HERSHEY_TRIPLEX = 4,\n        /// <summary>\n        /// HERSHEY_COMPLEX_SMALL\n        /// </summary>\n        HERSHEY_COMPLEX_SMALL = 5,\n        /// <summary>\n        /// HERSHEY_SCRIPT_SIMPLEX\n        /// </summary>\n        HERSHEY_SCRIPT_SIMPLEX = 6,\n        /// <summary>\n        /// HERSHEY_SCRIPT_COMPLEX\n        /// </summary>\n        HERSHEY_SCRIPT_COMPLEX = 7\n    }\n\n    /// <summary>\n    /// Managed structure equivalent to CvFont\n    /// </summary>\n    [StructLayout(LayoutKind.Sequential)]\n    public struct Font\n    {\n        /// <summary>\n        /// For QT\n        /// </summary>\n        private IntPtr fontName;\n        /// <summary>\n        /// For QT\n        /// </summary>\n        private CvScalar color;\n\n        ///<summary>\n        /// Font type\n        ///</summary>\n        public FontTypes FontType;\n        ///<summary>\n        /// font data and metrics \n        ///</summary>\n        private IntPtr ascii;\n        /// <summary>\n        /// \n        /// </summary>\n        private IntPtr greek;\n        /// <summary>\n        /// \n        /// </summary>\n        private IntPtr cyrillic;\n        /// <summary>\n        /// Horizontal scale. If equal to 1.0f, the characters have the original width depending on the font type. If equal to 0.5f, the characters are of half the original width.\n        /// </summary>\n        public float HorizontalScale;\n        /// <summary>\n        /// Vertical scale. If equal to 1.0f, the characters have the original height depending on the font type. If equal to 0.5f, the characters are of half the original height.\n        /// </summary>\n        public float VerticalScale;\n        ///<summary>\n        /// Approximate tangent of the character slope relative to the vertical line. Zero value means a non-italic font, 1.0f means 45 slope, etc. thickness Thickness of lines composing letters outlines. The function cvLine is used for drawing letters.\n        ///</summary>\n        public float Shear;\n        ///<summary>\n        /// Thickness of the text strokes.\n        ///</summary>\n        public int Thickness;\n        ///<summary>\n        /// Horizontal interval between letters.\n        ///</summary>\n        private float dx;\n        /// <summary>\n        /// Type of the strokes.\n        /// </summary>\n        private LineTypes LineType;\n\n        /// <summary>\n        /// Create a Font of the specific type, horizontal scale and vertical scale\n        /// </summary>\n        /// <param name=\"type\">The type of the font.</param>\n        /// <param name=\"hscale\">The horizontal scale of the font.</param>\n        /// <param name=\"vscale\">The vertical scale of the font.</param>\n        /// <param name=\"thickness\">Font thickness.</param>\n        public Font(FontTypes type, double hscale, double vscale, int thickness = 1)\n            : this()\n        {\n            CvCoreInvoke.cvInitFont(ref this, type, hscale, vscale, 0, thickness, LineTypes.EightConnected);\n        }\n\n        /// <summary>\n        /// Calculates the binding rectangle for the given text string when the font is used\n        /// </summary>\n        /// <param name=\"text\">Input string</param>\n        /// <param name=\"baseline\">y-coordinate of the baseline relatively to the bottom-most text point</param>\n        /// <returns>size of the text string. Height of the text does not include the height of character parts that are below the baseline</returns>\n        public Size GetTextSize(string text, int baseline)\n        {\n            var size = new Size();\n            CvCoreInvoke.cvGetTextSize(text, ref this, ref size, ref baseline);\n            return size;\n        }\n\n        /// <summary>\n        /// Hershey duplex font with vertical scale of two.\n        /// </summary>\n        public static Font Big = new Font(FontTypes.HERSHEY_DUPLEX, 1, 2);\n        /// <summary>\n        /// Hershey duplex font with vertical scale of 0.5.\n        /// </summary>\n        public static Font Normal = new Font(FontTypes.HERSHEY_DUPLEX, 1, 0.5f);\n        /// <summary>\n        /// Hershey duplex font with vertical scale of 0.25.\n        /// </summary>\n        public static Font Small = new Font(FontTypes.HERSHEY_DUPLEX, 1, 0.25f); \n    }\n\n    /// <summary>\n    /// CV's 4 element vector.\n    /// </summary>\n    internal struct CvScalar\n    {\n        /// <summary>\n        /// First value.\n        /// </summary>\n        public double V0;\n        /// <summary>\n        /// Second value.\n        /// </summary>\n        public double V1;\n        /// <summary>\n        /// Third value.\n        /// </summary>\n        public double V2;\n        /// <summary>\n        /// Fourth value.\n        /// </summary>\n        public double V3;\n    }\n\n    /// <summary>\n    /// The type of line for drawing\n    /// </summary>\n    internal enum LineTypes\n    {\n        /// <summary>\n        /// 8-connected\n        /// </summary>\n        EightConnected = 8,\n        /// <summary>\n        /// 4-connected\n        /// </summary>\n        FourConnected = 4,\n        /// <summary>\n        /// Antialias\n        /// </summary>\n        Antialiased = 16\n    }\n\n    /// <summary>\n    /// Internal class for OpenCV highgui library invocation.\n    /// </summary>\n    internal static class CvCoreInvoke\n    {\n        public const CallingConvention CvCallingConvention = CallingConvention.Cdecl;\n        public const string OPENCV_CORE_LIBRARY = \"opencv_core2412\";\n\n        #region Base\n\n        /// <summary>\n        /// Clones the provided image.\n        /// </summary>\n        /// <param name=\"image\">Image to clone.</param>\n        /// <returns>Cloned image.</returns>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern IplImage* cvCloneImage(IplImage* image);\n\n        /// <summary>\n        /// Releases the provided image.\n        /// </summary>\n        /// <param name=\"image\">Image to release.</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvReleaseImage(IplImage** image);\n\n        /// <summary>\n        /// Calculates the weighted sum of two arrays.\n        /// </summary>\n        /// <param name=\"src1\">First input image.</param>\n        /// <param name=\"alpha\">Weight for the first array elements.</param>\n        /// <param name=\"src2\">Second input array of the same size and channel number as src1.</param>\n        /// <param name=\"beta\">Weight of the second array elements.</param>\n        /// <param name=\"gamma\">Scalar added to each sum.</param>\n        /// <param name=\"dst\">Destination array.</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvAddWeighted(IplImage* src1, double alpha, IplImage* src2, double beta, double gamma, IplImage* dst);\n\n        #endregion\n\n        /// <summary>\n        /// Draws the line segment between pt1 and pt2 points in the image. The line is clipped by the image or ROI rectangle. For non-antialiased lines with integer coordinates the 8-connected or 4-connected Bresenham algorithm is used. Thick lines are drawn with rounding endings. Antialiased lines are drawn using Gaussian filtering.\n        /// </summary>\n        /// <param name=\"img\">The image</param>\n        /// <param name=\"pt1\">First point of the line segment</param>\n        /// <param name=\"pt2\">Second point of the line segment</param>\n        /// <param name=\"color\">Line color</param>\n        /// <param name=\"thickness\">Line thickness. </param>\n        /// <param name=\"lineType\">Type of the line:\n        /// 8 (or 0) - 8-connected line.\n        /// 4 - 4-connected line.\n        /// CV_AA - antialiased line. \n        /// </param>\n        /// <param name=\"shift\">Number of fractional bits in the point coordinates</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvLine(IplImage* img, Point pt1, Point pt2,\n                                                CvScalar color, int thickness,\n                                                LineTypes lineType, int shift);\n\n        /// <summary>\n        /// Draws a single or multiple polygonal curves\n        /// </summary>\n        /// <param name=\"img\">Image</param>\n        /// <param name=\"pts\">Array of pointers to polylines</param>\n        /// <param name=\"npts\">Array of polyline vertex counters</param>\n        /// <param name=\"contours\">Number of polyline contours</param>\n        /// <param name=\"isClosed\">\n        /// Indicates whether the polylines must be drawn closed. \n        /// If !=0, the function draws the line from the last vertex of every contour to the first vertex.\n        /// </param>\n        /// <param name=\"color\">Polyline color</param>\n        /// <param name=\"thickness\">Thickness of the polyline edges</param>\n        /// <param name=\"lineType\">Type of the line segments, see cvLine description</param>\n        /// <param name=\"shift\">Number of fractional bits in the vertex coordinates</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvPolyLine(IplImage* img, [In]IntPtr[] pts, [In]int[] npts, int contours, [MarshalAs(UnmanagedType.Bool)]  bool isClosed,\n                                                    CvScalar color, int thickness, \n                                                    LineTypes lineType, int shift);\n\n        /// <summary>\n        /// Draws a rectangle with two opposite corners pt1 and pt2\n        /// </summary>\n        /// <param name=\"img\">Image</param>\n        /// <param name=\"pt1\">A rectangle vertex</param>\n        /// <param name=\"pt2\">Opposite rectangle vertex</param>\n        /// <param name=\"color\">Line color </param>\n        /// <param name=\"thickness\">Thickness of lines that make up the rectangle. Negative values make the function to draw a filled rectangle.</param>\n        /// <param name=\"lineType\">Type of the line</param>\n        /// <param name=\"shift\">Number of fractional bits in the point coordinates</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvRectangle(IplImage* img, Point pt1, Point pt2,\n                                                     CvScalar color, int thickness,\n                                                     LineTypes lineType, int shift);\n\n        /// <summary>\n        /// Draws a rectangle specified by a CvRect structure\n        /// </summary>\n        /// /// <param name=\"img\">Image</param>\n        /// <param name=\"rect\">The rectangle to be drawn</param>\n        /// <param name=\"color\">Line color </param>\n        /// <param name=\"thickness\">Thickness of lines that make up the rectangle. Negative values make the function to draw a filled rectangle.</param>\n        /// <param name=\"lineType\">Type of the line</param>\n        /// <param name=\"shift\">Number of fractional bits in the point coordinates</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvRectangleR(IplImage* img, Rectangle rect,\n                                                      CvScalar color, int thickness,\n                                                      LineTypes lineType, int shift);\n\n        /// <summary>\n        /// Draws a simple or filled circle with given center and radius. The circle is clipped by ROI rectangle.\n        /// </summary>\n        /// <param name=\"img\">Image where the circle is drawn</param>\n        /// <param name=\"center\">Center of the circle</param>\n        /// <param name=\"radius\">Radius of the circle.</param>\n        /// <param name=\"color\">Color of the circle</param>\n        /// <param name=\"thickness\">Thickness of the circle outline if positive, otherwise indicates that a filled circle has to be drawn</param>\n        /// <param name=\"lineType\">Type of the circle boundary</param>\n        /// <param name=\"shift\">Number of fractional bits in the center coordinates and radius value</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvCircle(IplImage* img, Point center, int radius,\n                                                  CvScalar color, int thickness,\n                                                  LineTypes lineType, int shift);\n\n        /// <summary>\n        /// Draws a simple or thick elliptic arc or fills an ellipse sector. The arc is clipped by ROI rectangle. A piecewise-linear approximation is used for antialiased arcs and thick arcs. All the angles are given in degrees.\n        /// </summary>\n        /// <param name=\"img\">Image</param>\n        /// <param name=\"center\">Center of the ellipse</param>\n        /// <param name=\"axes\">Length of the ellipse axes</param>\n        /// <param name=\"angle\">Rotation angle</param>\n        /// <param name=\"startAngle\">Starting angle of the elliptic arc</param>\n        /// <param name=\"endAngle\">Ending angle of the elliptic arc</param>\n        /// <param name=\"color\">Ellipse color</param>\n        /// <param name=\"thickness\">Thickness of the ellipse arc</param>\n        /// <param name=\"lineType\">Type of the ellipse boundary</param>\n        /// <param name=\"shift\">Number of fractional bits in the center coordinates and axes' values</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvEllipse(IplImage* img, Point center, Size axes, double angle, double startAngle, double endAngle,\n                                                   CvScalar color, int thickness,\n                                                   LineTypes lineType, int shift);\n\n        /// <summary>\n        /// Draws contour outlines in the image if thickness &gt;=0 or fills area bounded by the contours if thickness&lt;0.\n        /// </summary>\n        /// <param name=\"img\">Image where the contours are to be drawn. Like in any other drawing function, the contours are clipped with the ROI</param>\n        /// <param name=\"contour\">Pointer to the first contour</param>\n        /// <param name=\"externalColor\">Color of the external contours</param>\n        /// <param name=\"holeColor\">Color of internal contours </param>\n        /// <param name=\"maxLevel\">Maximal level for drawn contours. If 0, only contour is drawn. If 1, the contour and all contours after it on the same level are drawn. If 2, all contours after and all contours one level below the contours are drawn, etc. If the value is negative, the function does not draw the contours following after contour but draws child contours of contour up to abs(maxLevel)-1 level. </param>\n        /// <param name=\"thickness\">Thickness of lines the contours are drawn with. If it is negative the contour interiors are drawn</param>\n        /// <param name=\"lineType\">Type of the contour segments</param>\n        /// <param name=\"offset\">Shift all the point coordinates by the specified value. It is useful in case if the contours retrived in some image ROI and then the ROI offset needs to be taken into account during the rendering. </param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvDrawContours(IplImage* img, IntPtr contour,\n                                                        CvScalar externalColor, CvScalar holeColor, int maxLevel, int thickness,\n                                                        LineTypes lineType, Point offset);\n\n        /// <summary>\n        /// Fills convex polygon interior. This function is much faster than The function cvFillPoly and can fill not only the convex polygons but any monotonic polygon, i.e. a polygon whose contour intersects every horizontal line (scan line) twice at the most\n        /// </summary>\n        /// <param name=\"img\">Image</param>\n        /// <param name=\"pts\">Array of pointers to a single polygon</param>\n        /// <param name=\"npts\">Polygon vertex counter</param>\n        /// <param name=\"color\">Polygon color</param>\n        /// <param name=\"lineType\">Type of the polygon boundaries</param>\n        /// <param name=\"shift\">Number of fractional bits in the vertex coordinates</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvFillConvexPoly(IplImage* img, [In] Point[] pts, int npts,\n                                                          CvScalar color, \n                                                          LineTypes lineType, int shift);\n\n        #region Text\n        /// <summary>\n        /// Initializes the font structure that can be passed to text rendering functions\n        /// </summary>\n        /// <param name=\"font\">Pointer to the font structure initialized by the function</param>\n        /// <param name=\"fontFace\">Font name identifier. Only a subset of Hershey fonts are supported now</param>\n        /// <param name=\"hscale\">Horizontal scale. If equal to 1.0f, the characters have the original width depending on the font type. If equal to 0.5f, the characters are of half the original width</param>\n        /// <param name=\"vscale\">Vertical scale. If equal to 1.0f, the characters have the original height depending on the font type. If equal to 0.5f, the characters are of half the original height</param>\n        /// <param name=\"shear\">Approximate tangent of the character slope relative to the vertical line. Zero value means a non-italic font, 1.0f means 45 slope, etc. thickness Thickness of lines composing letters outlines. The function cvLine is used for drawing letters</param>\n        /// <param name=\"thickness\">Thickness of the text strokes</param>\n        /// <param name=\"lineType\">Type of the strokes</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvInitFont(ref Font font, FontTypes fontFace, double hscale, double vscale, double shear,\n                                                    int thickness, LineTypes lineType);\n\n        /// <summary>\n        /// Renders the text in the image with the specified font and color. The printed text is clipped by ROI rectangle. Symbols that do not belong to the specified font are replaced with the rectangle symbol.\n        /// </summary>\n        /// <param name=\"img\">Input image</param>\n        /// <param name=\"text\">String to print</param>\n        /// <param name=\"org\">Coordinates of the bottom-left corner of the first letter</param>\n        /// <param name=\"font\">Pointer to the font structure</param>\n        /// <param name=\"color\">Text color</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public unsafe static extern void cvPutText(IplImage* img, [MarshalAs(UnmanagedType.LPStr)] String text, Point org, ref Font font, CvScalar color);\n\n        /// <summary>\n        /// Calculates the binding rectangle for the given text string when a specified font is used\n        /// </summary>\n        /// <param name=\"textString\">Input string</param>\n        /// <param name=\"font\">The font structure</param>\n        /// <param name=\"textSize\">Resultant size of the text string. Height of the text does not include the height of character parts that are below the baseline</param>\n        /// <param name=\"baseline\">y-coordinate of the baseline relatively to the bottom-most text point</param>\n        [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)]\n        public static extern void cvGetTextSize([MarshalAs(UnmanagedType.LPStr)] String textString, ref Font font, ref Size textSize, ref int baseline);\n        #endregion\n    }\n\n   \n}\n"
  },
  {
    "path": "Source/UI.Image/Base/CvInvoke.cs",
    "content": "#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Security;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// OpenCV image load mode.\n    /// </summary>\n    internal enum WindowSizing : int\n    {\n       Normal = 0x00000000,\n       AutoSize = 0x00000001\n    }\n\n    /// <summary>\n    /// Internal class for OpenCV core / highgui library invocation.\n    /// </summary>\n    static class CvInvoke\n    {\n        public const CallingConvention CvCallingConvention = CallingConvention.Cdecl;\n        public const string OPENCV_HIGHGUI_LIBRARY = \"opencv_highgui2412\";\n\n\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\n        public static extern void cvNamedWindow(string name, WindowSizing sizing);\n\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\n        public static extern void cvShowImage(string name, ref CvMat image);\n\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\n        public static extern void cvWaitKey(int delay);\n\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\n        public static extern void cvDestroyAllWindows();\n\n        [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)]\n        public static extern double cvGetWindowProperty(string name, int prop_id);\n    }\n}\n"
  },
  {
    "path": "Source/UI.Image/Drawing.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2018\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\nusing System.Drawing;\nusing DotImaging.Primitives2D;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides extensions for color format conversion to and from CvSclalar.\n    /// </summary>\n    internal static class ColorCvScalarConversionExtensions\n    {\n        public static CvScalar ToCvScalar(this Bgr<byte> color)\n        {\n            return new CvScalar{ V0 = color.B, V1 = color.G, V2 = color.R, V3 = Byte.MaxValue };\n        }\n\n        public static CvScalar ToCvScalar(this Bgra<byte> color)\n        {\n            return new CvScalar{ V0 = color.B, V1 = color.G, V2 = color.R, V3 = color.A };\n        }\n    }\n\n    /// <summary>\n    /// Provides extension drawing methods which operate on color RGB/RGBA images.\n    /// </summary>\n    public static class DrawingNativeImage\n    {\n        internal unsafe static void Draw(Image<Bgr<byte>> image, byte opacity, Action<IplImage> drawingAction)\n        {\n            var cvImg = image.AsCvIplImage();\n            var cvOverlayImPtr = CvCoreInvoke.cvCloneImage(&cvImg);\n\n            drawingAction(*cvOverlayImPtr);\n            CvCoreInvoke.cvAddWeighted(cvOverlayImPtr, (float)opacity / Byte.MaxValue, &cvImg, 1 - (float)opacity / Byte.MaxValue, 0, &cvImg);\n\n            CvCoreInvoke.cvReleaseImage(&cvOverlayImPtr);\n        }\n\n        #region Rectangle\n\n        /// <summary>\n        /// Draws rectangle.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <param name=\"color\">Object's color.</param>\n        /// <param name=\"thickness\">Border thickness (-1 to fill the object).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawRectangle(this Image<Bgr<byte>> image, Rectangle rect, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            if (float.IsNaN(rect.X) || float.IsNaN(rect.Y))\n                return;\n\n            Draw(image, opacity, cvImg =>\n            {\n                CvCoreInvoke.cvRectangleR(&cvImg, rect, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0);\n            });\n        }\n\n        #endregion\n\n        #region Text\n\n        /// <summary>\n        /// Draws text on the provided image.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"text\">User text.</param>\n        /// <param name=\"font\">Font.</param>\n        /// <param name=\"botomLeftPoint\">Bottom-left point.</param>\n        /// <param name=\"color\">Text color.</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawText(this Image<Bgr<byte>> image, string text, Font font, Point botomLeftPoint, Bgr<byte> color, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg =>\n            {\n                CvCoreInvoke.cvPutText(&cvImg, text, botomLeftPoint, ref font, color.ToCvScalar());\n            });\n        }\n\n        #endregion\n\n        #region Box & Ellipse\n\n        /// <summary>\n        /// Draws Box2D.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"box\">Box 2D.</param>\n        /// <param name=\"color\">Object's color.</param>\n        /// <param name=\"thickness\">Border thickness (-1 to fill the object).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void Draw2DBox(this Image<Bgr<byte>> image, Box2D box, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            if (thickness < 1)\n                throw new NotSupportedException(\"Only positive values are valid!\");\n\n            var vertices = box.GetVertices();\n\n            Draw(image, opacity, cvImg =>\n            {\n                for (int i = 0; i < vertices.Length; i++)\n                {\n                    int idx2 = (i + 1) % vertices.Length;\n\n                    CvCoreInvoke.cvLine(&cvImg, vertices[i].Round(), vertices[idx2].Round(),\n                                           color.ToCvScalar(), thickness,\n                                           LineTypes.EightConnected, 0);\n                }\n            });\n        }\n\n        /// <summary>\n        /// Draws ellipse.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"ellipse\">Ellipse.</param>\n        /// <param name=\"color\">Object's color.</param>\n        /// <param name=\"thickness\">Border thickness (-1 to fill the object).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawEllipse(this Image<Bgr<byte>> image, Ellipse ellipse, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg =>\n            {\n                CvCoreInvoke.cvEllipse(&cvImg, ellipse.Center.Round(), Size.Round(ellipse.Size), ellipse.Angle,\n                                       0, 360, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0);\n            });\n        }\n\n        #endregion\n\n        #region Contour\n\n        /// <summary>\n        /// Draws contour.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"polygon\">Contour points.</param>\n        /// <param name=\"color\">Contour color.</param>\n        /// <param name=\"thickness\">Contours thickness (it does not support values smaller than 1).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawPolygon(this Image<Bgr<byte>> image, Point[] polygon, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            var contourHandle = GCHandle.Alloc(polygon, GCHandleType.Pinned);\n\n            Draw(image, opacity, cvImg =>\n            {\n                //TODO - noncritical: implement with cvContour\n                CvCoreInvoke.cvPolyLine(&cvImg, new IntPtr[] { contourHandle.AddrOfPinnedObject() }, new int[] { polygon.Length }, 1,\n                                           true, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0);\n            });\n\n            contourHandle.Free();\n        }\n\n        #endregion\n\n        #region Circle\n\n        /// <summary>\n        /// Draws circle.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"circle\">Circle</param>\n        /// <param name=\"color\">Circle color.</param>\n        /// <param name=\"thickness\">Contours thickness.</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawCircle(this Image<Bgr<byte>> image, Circle circle, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg =>\n            {\n                var center = new Point(circle.X, circle.Y);\n\n                CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(),\n                                      thickness, LineTypes.EightConnected, 0);\n            });\n        }\n\n        /// <summary>\n        /// Draws circles.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"circles\">Circles</param>\n        /// <param name=\"color\">Circle color.</param>\n        /// <param name=\"thickness\">Contours thickness.</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawCircles(this Image<Bgr<byte>> image, IEnumerable<Circle> circles, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg =>\n            {\n                foreach (var circle in circles)\n                {\n                    var center = new Point(circle.X, circle.Y);\n\n                    CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(),\n                                          thickness, LineTypes.EightConnected, 0);\n                }\n            });\n        }\n\n        #endregion\n\n        #region Annotations\n\n        /// <summary>\n        /// Draws rectangle with the specified text on top.\n        /// </summary>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"rect\">User specified area to annotate.</param>\n        /// <param name=\"text\">Label.</param>\n        /// <param name=\"font\">Font to use.</param>\n        public static void DrawAnnotation(this Image<Bgr<byte>> image, Rectangle rect, string text, Font font)\n        {\n            const int VERTICAL_OFFSET = 5;\n\n            image.DrawRectangle(rect, Bgr<byte>.Red, 1);\n\n            var textSize = font.GetTextSize(text, 0);\n            var bottomLeftPt = new Point(rect.X + rect.Width / 2 - textSize.Width / 2, rect.Top - VERTICAL_OFFSET);\n            image.DrawText(text, font, bottomLeftPt, Bgr<byte>.Black);\n        }\n\n        #endregion\n    }\n\n    /// <summary>\n    /// Provides extension drawing methods which operate on color RGB/RGBA images.\n    /// </summary>\n    public static class Drawing\n    {\n        unsafe static void Draw(Bgr<byte>[,] image, byte opacity, Action<IplImage> drawingAction)\n        {\n            using (var uImg = image.Lock())\n                DrawingNativeImage.Draw(uImg, opacity, drawingAction);\n        }\n\n        #region Rectangle\n\n        /// <summary>\n        /// Draws rectangle.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"rect\">Rectangle.</param>\n        /// <param name=\"color\">Object's color.</param>\n        /// <param name=\"thickness\">Border thickness (-1 to fill the object).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawRectangle(this Bgr<byte>[,] image, Rectangle rect, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            if (float.IsNaN(rect.X) || float.IsNaN(rect.Y))\n                return;\n\n            Draw(image, opacity, cvImg => \n            {\n                CvCoreInvoke.cvRectangleR(&cvImg, rect, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0);\n            });\n        }\n\n        #endregion\n\n        #region Text\n\n        /// <summary>\n        /// Draws text on the provided image.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"text\">User text.</param>\n        /// <param name=\"font\">Font.</param>\n        /// <param name=\"botomLeftPoint\">Bottom-left point.</param>\n        /// <param name=\"color\">Text color.</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawText(this Bgr<byte>[,] image, string text, Font font, Point botomLeftPoint, Bgr<byte> color, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg => \n            {\n                CvCoreInvoke.cvPutText(&cvImg, text, botomLeftPoint, ref font, color.ToCvScalar());\n            });\n        }\n\n        #endregion\n\n        #region Box & Ellipse\n\n        /// <summary>\n        /// Draws Box2D.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"box\">Box 2D.</param>\n        /// <param name=\"color\">Object's color.</param>\n        /// <param name=\"thickness\">Border thickness (-1 to fill the object).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void Draw2DBox(this Bgr<byte>[,] image, Box2D box, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            if (thickness < 1)\n                throw new NotSupportedException(\"Only positive values are valid!\");\n\n            var vertices = box.GetVertices();\n\n            Draw(image, opacity, cvImg => \n            {\n                for (int i = 0; i < vertices.Length; i++)\n                {\n                    int idx2 = (i + 1) % vertices.Length;\n\n                    CvCoreInvoke.cvLine(&cvImg, vertices[i].Round(), vertices[idx2].Round(),\n                                           color.ToCvScalar(), thickness,\n                                           LineTypes.EightConnected, 0);\n                }\n            });\n        }\n\n        /// <summary>\n        /// Draws ellipse.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"ellipse\">Ellipse.</param>\n        /// <param name=\"color\">Object's color.</param>\n        /// <param name=\"thickness\">Border thickness (-1 to fill the object).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawEllipse(this Bgr<byte>[,] image, Ellipse ellipse, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg =>\n            {\n                CvCoreInvoke.cvEllipse(&cvImg, ellipse.Center.Round(), Size.Round(ellipse.Size), ellipse.Angle,\n                                       0, 360, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0);\n            });\n        }\n\n        #endregion\n\n        #region Contour\n\n        /// <summary>\n        /// Draws contour.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"polygon\">Contour points.</param>\n        /// <param name=\"color\">Contour color.</param>\n        /// <param name=\"thickness\">Contours thickness (it does not support values smaller than 1).</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawPolygon(this Bgr<byte>[,] image, Point[] polygon, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            var contourHandle = GCHandle.Alloc(polygon, GCHandleType.Pinned);\n\n            Draw(image, opacity, cvImg =>\n            {\n                //TODO - noncritical: implement with cvContour\n                CvCoreInvoke.cvPolyLine(&cvImg, new IntPtr[] { contourHandle.AddrOfPinnedObject() }, new int[] { polygon.Length }, 1,\n                                           true, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0);\n            });\n\n            contourHandle.Free();\n        }\n\n        #endregion\n\n        #region Circle\n\n        /// <summary>\n        /// Draws circle.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"circle\">Circle</param>\n        /// <param name=\"color\">Circle color.</param>\n        /// <param name=\"thickness\">Contours thickness.</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawCircle(this Bgr<byte>[,] image, Circle circle, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg =>\n            {\n                var center = new Point(circle.X, circle.Y);\n\n                CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(),\n                                      thickness, LineTypes.EightConnected, 0);\n            });\n        }\n\n        /// <summary>\n        /// Draws circles.\n        /// </summary>\n        /// <param name=\"image\">Input image.</param>\n        /// <param name=\"circles\">Circles</param>\n        /// <param name=\"color\">Circle color.</param>\n        /// <param name=\"thickness\">Contours thickness.</param>\n        /// <param name=\"opacity\">Sets alpha channel where 0 is transparent and 255 is full opaque.</param>\n        public unsafe static void DrawCircles(this Bgr<byte>[,] image, IEnumerable<Circle> circles, Bgr<byte> color, int thickness, byte opacity = Byte.MaxValue)\n        {\n            Draw(image, opacity, cvImg =>\n            {\n                foreach (var circle in circles)\n                {\n                    var center = new Point(circle.X, circle.Y);\n\n                    CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(),\n                                          thickness, LineTypes.EightConnected, 0);\n                }\n            });\n        }\n\n        #endregion\n\n        #region Annotations\n\n        /// <summary>\n        /// Draws rectangle with the specified text on top.\n        /// </summary>\n        /// <param name=\"image\">Image.</param>\n        /// <param name=\"rect\">User specified area to annotate.</param>\n        /// <param name=\"text\">Label.</param>\n        /// <param name=\"font\">Font to use.</param>\n        public static void DrawAnnotation(this Bgr<byte>[,] image, Rectangle rect, string text, Font font)\n        {\n            const int VERTICAL_OFFSET = 5;\n\n            image.DrawRectangle(rect, Bgr<byte>.Red, 1);\n\n            var textSize = font.GetTextSize(text, 0);\n            var bottomLeftPt = new Point(rect.X + rect.Width / 2 - textSize.Width / 2, rect.Top - VERTICAL_OFFSET);\n            image.DrawText(text, font, bottomLeftPt, Bgr<byte>.Black);\n        }\n\n        #endregion\n    }\n\n\n}\n"
  },
  {
    "path": "Source/UI.Image/ImageUI.cs",
    "content": "﻿#region Licence and Terms\n// DotImaging Framework\n// https://github.com/dajuric/dot-imaging\n//\n// Copyright © Darko Jurić, 2014-2019\n// darko.juric2@gmail.com\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n#endregion\n\nusing System;\n\nnamespace DotImaging\n{\n    /// <summary>\n    /// Provides simple standalone UI elements throughout static methods or extensions.\n    /// </summary>\n    public static class ImageUI\n    {\n        /// <summary>\n        /// Closes all UI controls if displayed.\n        /// </summary>\n        public static void CloseAll()\n        {\n            CvInvoke.cvDestroyAllWindows();\n        }\n\n        /// <summary>\n        /// Displays the specified image in a window and pauses the execution flow.\n        /// </summary>\n        /// <param name=\"image\">Image to show.</param>\n        /// <param name=\"windowTitle\">Window title (ID).</param>\n        /// <param name=\"autoSize\">True to adjust form to the image size, false otherwise.</param>\n        public static void ShowDialog(this Bgr<byte>[,] image, string windowTitle = \"Image\", bool autoSize = false)\n        {\n            Show(image, windowTitle, autoSize);\n\n            while (CvInvoke.cvGetWindowProperty(windowTitle, 0) >= 0)\n                CvInvoke.cvWaitKey(5);\n        }\n\n        /// <summary>\n        /// Displays the specified image in a window (non blocking mode).\n        /// </summary>\n        /// <param name=\"image\">Image to show.</param>\n        /// <param name=\"windowTitle\">Window title (ID).</param>\n        /// <param name=\"autoSize\">True to adjust form to the image size, false otherwise.</param>\n        public static void Show(this Bgr<byte>[,] image, string windowTitle = \"Image\", bool autoSize = false)\n        {\n            CvInvoke.cvNamedWindow(windowTitle, autoSize ? WindowSizing.AutoSize : WindowSizing.Normal);\n\n            using (var uIm = image.Lock())\n            {\n                var mat = uIm.AsCvMat();\n                CvInvoke.cvShowImage(windowTitle, ref mat);\n            }\n\n            CvInvoke.cvWaitKey(5);\n        }\n\n    }\n}\n"
  },
  {
    "path": "Source/UI.Image/UI.Image.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">  \n  <PropertyGroup>\n    <Platforms>x64</Platforms>\n    <AssemblyName>DotImaging.UI.Image</AssemblyName>\n    <RootNamespace>DotImaging</RootNamespace>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Image\\Image.csproj\" />\n    <ProjectReference Include=\"..\\Primitives2D\\Primitives2D.csproj\" />\n  </ItemGroup>\n  \t\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <DocumentationFile>bin\\DotImaging.UI.Image.xml</DocumentationFile>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Folder Include=\"runtimes\\win10-x64\\\" />\n    <Folder Include=\"runtimes\\ubuntu.16.04-x64\\\" />\n\n    <Content Include=\".nuSpec/readmeUI.Image.txt\">\n      <PackagePath>Readme.txt</PackagePath>\n    </Content>\n\n    <!-- Windows -->\n    <Content Include=\"runtimes\\win10-x64\\*.dll\">\n\t  <Link>runtimes\\win10-x64\\%(FileName)%(Extension)</Link>\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n      <PackagePath>runtimes/win-x64/native/</PackagePath>\n    </Content>\n\n    <!-- Linux -->\n    <Content Include=\"runtimes\\ubuntu.16.04-x64\\*.so*\">\n\t  <Link>runtimes\\win10-x64\\%(FileName)%(Extension)</Link>\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n      <PackagePath>runtimes/ubuntu.16.04-x64/native/</PackagePath>\n    </Content>\n  </ItemGroup>\n  \n  <!-- NuGet -->\n  <PropertyGroup>\n    <Version>5.3.0</Version>\n\n    <PackageId>DotImaging.UI.Image</PackageId>\n    <Description>\n      Image preview dialog and drawing.\n    </Description>\n    <PackageTags>UI, portable-UI, UI-extensions, DotImaging-UI</PackageTags>\n\n    <Authors>Darko Jurić</Authors>\n    <Copyright>Darko Jurić</Copyright>\n    <PackageLicenseUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt</PackageLicenseUrl>\n    <PackageIconUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png</PackageIconUrl>\n    <PackageProjectUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</PackageProjectUrl>\n    <RepositoryUrl>https://raw.githubusercontent.com/dajuric/dot-imaging/</RepositoryUrl>\n\n    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>\n    <PackageOutputPath>../../Deploy/NuGet/bin/</PackageOutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\".nuSpec\\readmeUI.Image.txt\">\n      <PackagePath>Readme.txt</PackagePath>\n    </Content>\n  </ItemGroup>\n</Project>\n"
  }
]